Skip to main content

Veelvoorkomende problemen met SAML-verificatie

Deze pagina biedt een algemeen overzicht van het Building Block Security Assertion Markup Language (SAML) 2.0. Daarnaast bespreken we veelvoorkomende problemen met eenmalige aanmelding (SSO) en technieken voor het oplossen van problemen met de SAML-verificatieprovider.

Belangrijk

Als om welke reden dan ook een bijgewerkt/nieuw XML-bestand met IdP-metagegevens wordt geüpload in de GUI van Blackboard op de pagina SAML-verificatie-instellingen in de sectie Instellingen voor identiteitsprovider voor een SAML-verificatieprovider, moeten de SAML B2 en die SAML-verificatieprovider ook worden ingeschakeld als Inactief/Beschikbaar, terwijl de SAML-verificatieprovider de status 'Actief' heeft, om ervoor te zorgen dat alle IdP-metagegevens in de cache worden gewist en dat de bijgewerkte IdP-metagegevens volledig worden benut.

Belangrijke terminologie

In dit artikel worden de volgende termen en afkortingen gebruikt:

  • SAML: Opmaaktaal voor beveiligingsbewering

  • IdP: Identiteitsprovider

  • SP: Dienstverlener

  • ADFS: Active Directory Federation service

  • GUI: Grafische gebruikersinterface. In de context van Blackboard betekent dit werken binnen de software.

SAML-configuratie-instellingen bewerken

Om makkelijker problemen met SAML-verificatie op te lossen, is het Building Block SAML in release 3200.2.0 uitgebreid met deze configuratie-instellingen en -opties:

  • Vervallimiet voor SAML-sessies definiëren

  • Type Signature Algorithm kiezen

  • Certificaten opnieuw genereren

  • De ResponseSkew-waarde aanpassen

Fouten en uitzonderingen

Fouten en uitzonderingen die met SAML te maken hebben, worden vastgelegd in de volgende logboeken:

  • /usr/local/blackboard/logs/bb-services-log.txt

  • /usr/local/blackboard/logs/tomcat/stdout-stderr-<datum>.log

  • /usr/local/blackboard/logs/tomcat/catalina-log.txt

Deze logboeken moeten altijd worden geraadpleegd als er een probleem is gemeld over SAML-verificatie.

SAML Tracer

Met iteraties voor SAML 2.0-verificatie kan het op een gegeven moment nodig zijn om de kenmerken te bevestigen/weergeven die daadwerkelijk worden vrijgegeven van de IdP en naar Blackboard worden verzonden tijdens het verificatieproces. Als de attributen van de IdP NIET zijn versleuteld in de SAML-reactie, kan de Firefox browser SAML tracer Add-on of Chrome SAML Message Decoder worden gebruikt om de attributen weer te geven.

Kenmerk niet goed toegewezen

Als het kenmerk met de gebruikersnaam niet correct is toegewezen zoals opgegeven in het veld Externe gebruikers-ID in de sectie SAML-kenmerken toewijzen op de pagina SAML-verificatie-instellingen in de GUI van Bb, wordt de volgende gebeurtenis geregistreerd in het logboek van Bb-services wanneer wordt geprobeerd zich aan te melden bij Bb via SAML-verificatie:

2016-06-28 12:48:12 -0400 - userName is null or empty

Een vergelijkbare Aanmeldingsfout! bericht dat in de browser wordt weergegeven: Blackboard kan zich momenteel niet aanmelden bij je account met eenmalige aanmelding. Neem contact op met uw beheerder voor hulp.

Een afbeelding van een aanmeldingsfoutmelding die in de browser wordt weergegeven en waarin staat dat Blackboard zich momenteel niet kan aanmelden bij je account met single-sing on. Neem contact op met uw beheerder voor hulp.

Er wordt een vermelding Authentication Failure toegevoegd aan het logboek bb-services:

2016-06-28 12:48:12 -0400 - BbSAMLExceptionHandleFilter - javax.servlet.ServletException: Authentication Failure
    at blackboard.auth.provider.saml.customization.handler.BbAuthenticationSuccessHandler.checkAuthenticationResult(BbAuthenticationSuccessHandler.java:81)
    at blackboard.auth.provider.saml.customization.handler.BbAuthenticationSuccessHandler.onAuthenticationSuccess(BbAuthenticationSuccessHandler.java:57)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.successfulAuthentication(AbstractAuthenticationProcessingFilter.java:331)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:245)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
[SNIP]
Oplossing

Je hebt twee opties om dit probleem op te lossen. Selecteer eerst de optie Accounts maken als ze niet bestaan in het systeem op de pagina SAML-verificatie-instellingen in de GUI van Blackboard. De tweede optie is om de waarde te bekijken van de kenmerken die door de IdP worden vrijgegeven. Dit kan via SAML tracer of Debug loggen als de kenmerken NIET zijn gecodeerd:

<saml2:Attribute Name="urn:oid:0.9.2342.19200300.100.1.3">
    <saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
                          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                          xsi:type="xs:anyType"
                          >bbuser_saml2@bbchjones.net</saml2:AttributeValue>
</saml2:Attribute>

en wijs de Kenmerknaam met de gewenste AttributeValue toe aan de Externe gebruikers-ID op de pagina SAML-verificatie-instellingen in de GUI van Blackboard.

Geen compatibele gegevensbron geselecteerd

Gebruikers kunnen zich niet aanmelden bij Blackboard via SAML-verificatie als de Gegevensbron voor de gebruikers niet is geselecteerd in de sectie Instellingen voor serviceproviders > compatibele gegevensbronnen op de pagina Instellingen voor SAML-verificatie in de GUI van Blackboard. De volgende gebeurtenis wordt geregistreerd in het Bb-service logboek wanneer wordt geprobeerd in te loggen op Blackboard via SAML-authenticatie:

2016-09-23 12:33:13 -0500 - userName is null or empty

Er wordt een Aanmeldingsfout! weergegeven in de browser, plus de vermelding Authentication Failure in het logboek bb-services:

2016-09-23 12:33:13 -0500 - BbSAMLExceptionHandleFilter - javax.servlet.ServletException: Authentication Failure
    at blackboard.auth.provider.saml.customization.handler.BbAuthenticationSuccessHandler.checkAuthenticationResult(BbAuthenticationSuccessHandler.java:82)
    at blackboard.auth.provider.saml.customization.handler.BbAuthenticationSuccessHandler.onAuthenticationSuccess(BbAuthenticationSuccessHandler.java:58)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.successfulAuthentication(AbstractAuthenticationProcessingFilter.java:331)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:245)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter (SecurityContextPersistenceFilter.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at sun.reflect.GeneratedMethodAccessor3399.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
        [SNIP]
Oplossing
  1. Vraag de gebruikersnaam van een gebruiker die zich niet kan aanmelden.

  2. Navigeer in de GUI van Blackboard naar Systeembeheerder > gebruikers en zoek naar de gebruiker.

  3. Kopieer de waarde voor Gegevensbronsleutel van de gebruiker.

  4. Ga naar Systeembeheer > Verificatie > "naam van provider" > Instellingen voor SAML-verificatie > Compatibele gegevensbronnen.

  5. Zet een vinkje naast die gegevensbronin de kolom Naam en selecteer Verzenden.

Foutbericht dat notatie van opgegeven URL onjuist is

Als OneLogin is geconfigureerd als de IdP voor de SAML-verificatieprovider in Blackboard, kan de fout Opgegeven URL is niet goed gevormd worden weergegeven op de pagina na het invoeren van de OneLogin-referenties bij het inloggen op Blackboard.

In het logboek bb-services wordt dan deze vermelding opgenomen:

2016-09-16 09:43:40 -0400 - Given URL is not well formed<P><span class="captionText">For reference, the Error ID is 17500f44-7809-4b9f-a272-3bed1d1af131.</span> - java.lang.IllegalArgumentException: Given URL is not well formed
    at org.opensaml.util.URLBuilder.<init>(URLBuilder.java:120)
    at org.opensaml.util.SimpleURLCanonicalizer.canonicalize(SimpleURLCanonicalizer.java:87)
    at org.opensaml.common.binding.decoding.BasicURLComparator.compare(BasicURLComparator.java:57)
    at org.opensaml.common.binding.decoding.BaseSAMLMessageDecoder.compareEndpointURIs(BaseSAMLMessageDecoder.java:173)
    at org.opensaml.common.binding.decoding.BaseSAMLMessageDecoder.checkEndpointURI(BaseSAMLMessageDecoder.java:213)
    at org.opensaml.saml2.binding.decoding.BaseSAML2MessageDecoder.decode(BaseSAML2MessageDecoder.java:72)
    at org.springframework.security.saml.processor.SAMLProcessorImpl.retrieveMessage(SAMLProcessorImpl.java:105)
    at org.springframework.security.saml.processor.SAMLProcessorImpl.retrieveMessage(SAMLProcessorImpl.java:172)
    at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:80)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    [SNIP]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.net.MalformedURLException: no protocol: {recipient}
    at java.net.URL.<init>(URL.java:593)
    at java.net.URL.<init>(URL.java:490)
    at java.net.URL.<init>(URL.java:439)
    at org.opensaml.util.URLBuilder.<init>(URLBuilder.java:77)
        ... 203 more
Oplossing
  1. Schakel de Firefox-invoegtoepassing SAML tracer in en repliceer het probleem.

  2. Kijk naar het begin van de gebeurtenis SAML POST:

    <samlp:Response Destination="{recipient}"
            ID="R8afbfbfee7292613f98ad4ec4115de7c6b385be6"
            InResponseTo="a3g2424154bb0gjh3737ii66dadbff4"
            IssueInstant="2016-09-16T18:49:09Z"
            Version="2.0"
            xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
            xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
            >
        <saml:Issuer>https://app.onelogin.com/saml/metadata/123456</saml:Issuer>
        [SNIP]
  3. Op regel 1 met het antwoord (Response) zie je dat de bestemming (Destination=) alleen is ingesteld op recipient (ontvanger).

  4. Laat de client naar de sectie Configuration van OneLogin gaan.

  5. Controleer of het veld Recipient leeg is.

  6. Kopieer de waarde van ACS (Consumer) URL, plak deze in het veld Recipient en selecteer Save.

Probleemscenario's voor IdP/SP

  1. Als er een fout wordt weergegeven voordat je wordt omgeleid naar de aanmeldingspagina van de IdP, zijn de metagegevens van de IdP mogelijk ongeldig.

  2. Als er een fout optreedt nadat je je hebt aangemeld bij de IdP, zijn dit de mogelijke oorzaken:

    1. Onjuiste koppeling van kenmerken tussen de SP en de IdP, of de IdP heeft geen geldige externe gebruikers-ID geretourneerd.

    2. De SAML-respons van de IdP is niet gevalideerd door de SP. Dit kan worden veroorzaakt door:

      • De IdP ondertekent de SAML-respons met een certificaat dat niet is uitgegeven door een erkende certificeringsinstantie, en het certificaat is niet aanwezig in de keystore van de SP.

      • De systeemklok van de SP staat niet goed.

Active Directory Federation Services (ADFS)

De kenmerknamen zijn hoofdlettergevoelig in de sectie SAML-kenmerken weergeven op de pagina SAML-verificatie-instellingen in de GUI van Blackboard. Dus als de Remote User IDsAMAccountName heeft voor de Attribute Name op de instellingenpagina en de daadwerkelijke SAML POST van de IdP heeft dit voor de Attribute Name in de AttributeStatement:

<AttributeStatement>
    <Attribute Name="SamAccountName>
        <AttributeValue>Test-User</AttributeValue>
    </Attribute>
</AttributeStatement>

Kan de gebruiker zich niet aanmelden. De waarde voor de kenmerknaam Remote User ID op de pagina SAML-verificatie-instellingen moet worden gewijzigd van sAMAccountName in SamAccountName.

Waarschuwing dat resource niet is gevonden of aanmeldingsfout!

Deze sectie bevat enkele van de veelvoorkomende problemen die kunnen voorkomen dat een gebruiker zich aanmeldt bij Blackboard via SAML-verificatie met ADFS wanneer De opgegeven bron is niet gevonden of je hebt geen toestemming om deze te openen of Aanmeldingsfout! bericht wordt weergegeven in de GUI van Blackboard.

Probleem 1

Nadat u de aanmeldingsgegevens op de ADFS-aanmeldingspagina hebt ingevoerd, kan er een fout worden weergegeven nadat deze is omgeleid naar de GUI van Blackboard: De opgegeven bron is niet gevonden of u hebt geen toestemming om deze te openen.

Foutmelding 'Er is geen opgegeven resource gevonden'

In het logboek stdout-stderr wordt dan deze melding vastgelegd:

INFO | jvm 1 | 2016/06/22 06:08:33 | - No mapping found for HTTP request with URI [/auth-saml/saml/SSO] in DispatcherServlet with name 'saml'

Het probleem treedt op omdat de methode noHandlerFound() wordt gebruikt in de code DispatcherServlet.java en het HTTP SSO-verzoek niet kan worden gevonden/toegewezen.

/**
 * No handler found -> set appropriate HTTP response status.
 * @param request current HTTP request
 * @param response current HTTP response
 * @throws Exception if preparing the response failed
 */
protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
 if (pageNotFoundLogger.isWarnEnabled()) {
  pageNotFoundLogger.warn("No mapping found for HTTP request with URI [" + getRequestUri(request) +
    "] in DispatcherServlet with name '" + getServletName() + "'");
 }
 if (this.throwExceptionIfNoHandlerFound) {
  throw new NoHandlerFoundException(request.getMethod(), getRequestUri(request),
    new ServletServerHttpRequest(request).getHeaders());
 }
 else {
  response.sendError(HttpServletResponse.SC_NOT_FOUND);
 }
}
Oplossing

Dit gebeurt meestal omdat de entiteits-id voor de SP die in de GUI van Blackboard is geconfigureerd, onjuist is. Dit kan worden opgelost door naar Systeembeheer > Verificatie > Instellingen voor SAML-verificatie > Instellingen serviceprovider te gaan en de waarde voor Entity ID aan te passen. Voor ADFS is de standaardconfiguratie voor de entiteits-idhttps://[Blackboard Server Hostname]/auth-saml/saml/Eenmalige aanmelding.

Opmerking

Als een school de URL wijzigt van de standaard-https://school.blackboard.com in https://their.school.edu, moet de entiteits-id in de GUI van Blackboard op de pagina SAML-verificatie-instellingen worden bijgewerkt naar https://their.school.edu/auth-saml/saml/Eenmalige aanmelding.

Probleem 2

Nadat u de aanmeldingsgegevens op de ADFS-aanmeldingspagina hebt ingevoerd, kan er een fout worden weergegeven nadat deze is omgeleid naar de GUI van Blackboard: De opgegeven bron is niet gevonden of u hebt geen toestemming om deze te openen.

In het logboek stdout-stderr wordt dan deze melding vastgelegd:

INFO  | jvm 1  | 2016/06/22 06:08:33 | - No mapping found for HTTP request with URI [/auth-saml/saml/SSO] in DispatcherServlet with name 'saml'

En deze melding in het catalina-logboek:

ERROR 2016-06-27 10:47:03,664 connector-6: userId=_2_1, sessionId=62536416FB80462298C92064A7022E50 org.opensaml.xml.encryption.Decrypter - Error decrypting the encrypted data element
org.apache.xml.security.encryption.XMLEncryptionException: Illegal key size
Original Exception was java.security.InvalidKeyException: Illegal key size
    at org.apache.xml.security.encryption.XMLCipher.decryptToByteArray(XMLCipher.java:1822)
    at org.opensaml.xml.encryption.Decrypter.decryptDataToDOM(Decrypter.java:596)
    at org.opensaml.xml.encryption.Decrypter.decryptUsingResolvedEncryptedKey(Decrypter.java:795)
    at org.opensaml.xml.encryption.Decrypter.decryptDataToDOM(Decrypter.java:535)
    at org.opensaml.xml.encryption.Decrypter.decryptDataToList(Decrypter.java:453)
    at org.opensaml.xml.encryption.Decrypter.decryptData(Decrypter.java:414)
    at org.opensaml.saml2.encryption.Decrypter.decryptData(Decrypter.java:141)
    at org.opensaml.saml2.encryption.Decrypter.decrypt(Decrypter.java:69)
    at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:199)
    at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:82)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
        [SNIP]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.security.InvalidKeyException: Illegal key size
    at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1039)
    at javax.crypto.Cipher.init(Cipher.java:1393)
    at javax.crypto.Cipher.init(Cipher.java:1327)
    at org.apache.xml.security.encryption.XMLCipher.decryptToByteArray(XMLCipher.java:1820)
        ... 205 more

En deze melding in het logboek bb-services:

2016-06-27 10:47:03 -0400 - unsuccessfulAuthentication - org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
    at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:100)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
    at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:87)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at sun.reflect.GeneratedMethodAccessor3422.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:277)
    at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:274)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAsPrivileged(Subject.java:549)
    at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:309)
    at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:249)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
    at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:55)
    at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:191)
    at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:187)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:186)
    at blackboard.auth.provider.saml.customization.filter.BbSAMLExceptionHandleFilter.doFilterInternal(BbSAMLExceptionHandleFilter.java:30)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at sun.reflect.GeneratedMethodAccessor3421.invoke(Unknown Source)
        [SNIP]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.opensaml.common.SAMLException: Response doesn't have any valid assertion which would pass subject validation
    at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:229)
    at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:87)
        ... 229 more

Het probleem doet zich voor omdat ADFS standaard de attributen versleutelt die worden verzonden met behulp van AES-256 en de Java-runtime die door Blackboard wordt gebruikt, AES-256 niet standaard ondersteunt.

Oplossing

Een universele oplossingsoptie is om een PowerShell te openen op de ADFS-server en de relying party die voor Blackboard is gemaakt, in te stellen om de kenmerken als niet-versleuteld te verzenden. Aangezien de communicatie volledig verloopt via SSL, heeft dit geen gevolgen voor de beveiliging van de verificatie. Het maakt het ook gemakkelijker om eventuele problemen op te sporen, omdat de attributen kunnen worden bekeken met behulp van foutopsporingstools zoals de Firefox-browser SAML tracer Add-on en een herstart van het Blackboard-systeem is niet vereist. Als je wilt instellen dat de relying party die voor Blackboard is gemaakt, de kenmerken als niet-versleuteld verzendt, open je een KrachtShell en voer je de volgende opdracht uit, waarbij je TargetName vervangt door de naam van de Relying Party Trust die zich in de ADFS-beheerconsole bevindt onder Vertrouwensrelaties > vertrouwensrelaties van relying party.

set-ADFSRelyingPartyTrust –TargetName "yourlearnserver.blackboard.com" –EncryptClaims $False

Na deze wijziging moet de ADFS-service opnieuw worden opgestart met het commando: Restart-Service ADFSSRV

Probleem 3

Nadat u de aanmeldingsgegevens op de ADFS-aanmeldingspagina hebt ingevoerd, kan er een fout worden weergegeven nadat deze is omgeleid naar de GUI van Blackboard: De opgegeven bron is niet gevonden of u hebt geen toestemming om deze te openen of Aanmeldingsfout!

In beide gevallen worden deze vergelijkbare SAML-gebeurtenissen vastgelegd in het logboek stdout-stderr:

INFO   | jvm 1    | 2016/09/06 20:33:04 | - /saml/login?apId=_107_1&redirectUrl=https%3A%2F%2Fbb.fraser.misd.net%2Fwebapps%2Fportal%2Fexecute%2FdefaultTab at position 1 of 10 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
INFO   | jvm 1    | 2016/09/06 20:33:04 | - No HttpSession currently exists
INFO   | jvm 1    | 2016/09/06 20:33:04 | - No SecurityContext was available from the HttpSession: null. A new one will be created.
INFO   | jvm 1    | 2016/09/06 20:33:04 | - /saml/login?apId=_107_1&redirectUrl=https%3A%2F%2Fbb.fraser.misd.net%2Fwebapps%2Fportal%2Fexecute%2FdefaultTab at position 2 of 10 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
INFO   | jvm 1    | 2016/09/06 20:33:04 | - /saml/login?apId=_107_1&redirectUrl=https%3A%2F%2Fbb.fraser.misd.net%2Fwebapps%2Fportal%2Fexecute%2FdefaultTab at position 3 of 10 in additional filter chain; firing Filter: 'HeaderWriterFilter'
INFO   | jvm 1    | 2016/09/06 20:33:04 | - /saml/login?apId=_107_1&redirectUrl=https%3A%2F%2Fbb.fraser.misd.net%2Fwebapps%2Fportal%2Fexecute%2FdefaultTab at position 4 of 10 in additional filter chain; firing Filter: 'FilterChainProxy'
INFO   | jvm 1    | 2016/09/06 20:33:04 | - Checking match of request : '/saml/login'; against '/saml/login/**'
INFO   | jvm 1    | 2016/09/06 20:33:04 | - /saml/login?apId=_107_1&redirectUrl=https%3A%2F%2Fbb.fraser.misd.net%2Fwebapps%2Fportal%2Fexecute%2FdefaultTab at position 1 of 1 in additional filter chain; firing Filter: 'SAMLEntryPoint'
INFO   | jvm 1    | 2016/09/06 20:33:04 | - Request for URI http://www.w3.org/2000/09/xmldsig#rsa-sha1
INFO   | jvm 1    | 2016/09/06 20:33:04 | - Request for URI http://www.w3.org/2000/09/xmldsig#rsa-sha1
INFO   | jvm 1    | 2016/09/06 20:33:04 | - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
INFO   | jvm 1    | 2016/09/06 20:33:04 | - SecurityContextHolder now cleared, as request processing completed
INFO   | jvm 1    | 2016/09/06 20:33:07 | - /saml/SSO at position 1 of 10 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
INFO   | jvm 1    | 2016/09/06 20:33:07 | - HttpSession returned null object for SPRING_SECURITY_CONTEXT
INFO   | jvm 1    | 2016/09/06 20:33:07 | - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@6708a718. A new one will be created.
INFO   | jvm 1    | 2016/09/06 20:33:07 | - /saml/SSO at position 2 of 10 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
INFO   | jvm 1    | 2016/09/06 20:33:07 | - /saml/SSO at position 3 of 10 in additional filter chain; firing Filter: 'HeaderWriterFilter'
INFO   | jvm 1    | 2016/09/06 20:33:07 | - /saml/SSO at position 4 of 10 in additional filter chain; firing Filter: 'FilterChainProxy'
INFO   | jvm 1    | 2016/09/06 20:33:07 | - Checking match of request : '/saml/sso'; against '/saml/login/**'
INFO   | jvm 1    | 2016/09/06 20:33:07 | - Checking match of request : '/saml/sso'; against '/saml/logout/**'
INFO   | jvm 1    | 2016/09/06 20:33:07 | - Checking match of request : '/saml/sso'; against '/saml/bbsamllogout/**'
INFO   | jvm 1    | 2016/09/06 20:33:07 | - Checking match of request : '/saml/sso'; against '/saml/sso/**'
INFO   | jvm 1    | 2016/09/06 20:33:07 | - /saml/SSO at position 1 of 1 in additional filter chain; firing Filter: 'SAMLProcessingFilter'
INFO   | jvm 1    | 2016/09/06 20:33:07 | - Authentication attempt using org.springframework.security.saml.SAMLAuthenticationProvider
INFO   | jvm 1    | 2016/09/06 20:33:07 | - Forwarding to /
INFO   | jvm 1    | 2016/09/06 20:33:07 | - DispatcherServlet with name 'saml' processing POST request for [/auth-saml/saml/SSO]
INFO   | jvm 1    | 2016/09/06 20:33:07 | - No mapping found for HTTP request with URI [/auth-saml/saml/SSO] in DispatcherServlet with name 'saml'
INFO   | jvm 1    | 2016/09/06 20:33:07 | - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
INFO   | jvm 1    | 2016/09/06 20:33:07 | - Successfully completed request
INFO   | jvm 1    | 2016/09/06 20:33:07 | - Skip invoking on
INFO   | jvm 1    | 2016/09/06 20:33:07 | - SecurityContextHolder now cleared, as request processing completed

Of deze vergelijkbare SAML-uitzonderingen in het logboek bb-services:

2016-11-29 09:04:24 -0500 - unsuccessfulAuthentication - org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
    at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:100)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
    at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:87)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at sun.reflect.GeneratedMethodAccessor853.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:282)
    at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:279)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAsPrivileged(Subject.java:549)
    at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314)
    at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)
    at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:46)
    at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:148)
    at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:144)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:143)
    at blackboard.auth.provider.saml.customization.filter.BbSAMLExceptionHandleFilter.doFilterInternal(BbSAMLExceptionHandleFilter.java:30)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at sun.reflect.GeneratedMethodAccessor853.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        [SNIP]
    at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:677)
    at blackboard.tomcat.valves.LoggingRemoteIpValve.invoke(LoggingRemoteIpValve.java:44)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:1110)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:785)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1425)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.opensaml.common.SAMLException: Response issue time is either too old or with date in the future, skew 60, time 2016-11-29T14:03:16.634Z
    at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:126)
    at blackboard.auth.provider.saml.customization.consumer.BbSAMLWebSSOProfileConsumerImpl.processAuthenticationResponse(BbSAMLWebSSOProfileConsumerImpl.java:40)
    at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:87)
        ... 230 more

Het probleem treedt op wanneer de ADFS-server en de Blackboard-appserver een tijdsafwijking hebben die dicht bij of langer ligt dan de standaardwaarde van 60 seconden.

Oplossing

Je hebt twee opties om dit probleem op te lossen:

  • Het handmatig synchroniseren van de klokken van de Blackboard-app-toepassingsservers en de ADFS-server. Voor Blackboard kan de huidige tijd en tijdzone van de server in een webbrowser worden weergegeven door /webapps/portal/healthCheck toe te voegen aan het einde van een Blackboard-URL.

    Voorbeeld: https://mhtest1.blackboard.com//webapps/portal/healthCheck

    Hostname: ip-10-145-49-11.ec2.internal
    Status: Active - Database connectivity established
    Running since: Sat, Dec 3, 2016 - 05:39:11 PM EST
    Time of request: Thu, Dec 8, 2016 - 05:12:43 PM EST

    Opmerking

    Een instelling kan de bovenstaande URL gebruiken om de tijdzone en klok van het Blackboard-systeem te vergelijken met die van hun ADFS-server, en deze items vervolgens zo nodig op de ADFS-server aan te passen, zodat ze gesynchroniseerd zijn met de Blackboard-site.

Probleem 4

Nadat u de aanmeldingsgegevens op de ADFS-aanmeldingspagina hebt ingevoerd, kan er een fout worden weergegeven nadat deze is omgeleid naar de GUI van Blackboard: De opgegeven bron is niet gevonden, of u hebt geen toestemming om deze te openen of Aanmeldingsfout!

In het logboek bb-services worden de volgende uitzonderingen opgenomen:

2016-11-01 12:47:19 -0500 - unsuccessfulAuthentication - org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
    at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:100)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
    at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:87)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at sun.reflect.GeneratedMethodAccessor929.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:282)
    at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:279)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAsPrivileged(Subject.java:549)
    at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314)
    at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)
    at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:46)
    at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:148)
    at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:144)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:143)
    at blackboard.auth.provider.saml.customization.filter.BbSAMLExceptionHandleFilter.doFilterInternal(BbSAMLExceptionHandleFilter.java:30)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
 [SNIP]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.opensaml.common.SAMLException: Response has invalid status code urn:oasis:names:tc:SAML:2.0:status:Responder, status message is null
    at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:113)
    at blackboard.auth.provider.saml.customization.consumer.BbSAMLWebSSOProfileConsumerImpl.processAuthenticationResponse(BbSAMLWebSSOProfileConsumerImpl.java:40)
    at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:87)
        ... 230 more
 2016-11-01 12:47:19 -0500 - BbSAMLExceptionHandleFilter - javax.servlet.ServletException: Unsuccessful Authentication
         at blackboard.auth.provider.saml.customization.filter.BbSAMLProcessingFilter.unsuccessfulAuthentication(BbSAMLProcessingFilter.java:31)
         at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:235)
         at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
         at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
         at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
         at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
         at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
         at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
         at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
         at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
         at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
         at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
         at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
         at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
         at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
         at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
         at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
         at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
         at sun.reflect.GeneratedMethodAccessor929.invoke(Unknown Source)
         at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
         at java.lang.reflect.Method.invoke(Method.java:498)
         at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:282)
         at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:279)
         at java.security.AccessController.doPrivileged(Native Method)
         at javax.security.auth.Subject.doAsPrivileged(Subject.java:549)
         at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314)
         at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253)
         at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)
         at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:46)
         at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:148)
         at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:144)
         at java.security.AccessController.doPrivileged(Native Method)
         at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:143)
         at blackboard.auth.provider.saml.customization.filter.BbSAMLExceptionHandleFilter.doFilterInternal(BbSAMLExceptionHandleFilter.java:30)
 [SNIP]
Oplossing
  1. Ga naar het configuratiescherm voor systeembeheer.

  2. Selecteer onder Integraties de optie Building Blocks.

  3. Selecteer Geïnstalleerde hulpprogramma's .

  4. Zoek Verificatieprovider - SAML in de lijst. Open het menu en selecteer Instellingen.

  5. Kies onder Instellingen voor handtekeningalgoritme de optie SHA-256 in de lijst. Nadat je een waarde hebt gekozen voor Type Signature Algorithm, start je het Building Block SAML opnieuw om de nieuwe instellingen toe te passen.

  6. Selecteer Verzenden om de wijzigingen op te slaan.

Probleem 5

Nadat u de aanmeldingsgegevens op de ADFS-aanmeldingspagina hebt ingevoerd, kan er een fout worden weergegeven nadat deze is omgeleid naar de GUI van Blackboard: De opgegeven bron is niet gevonden of u hebt geen toestemming om deze te openen of Aanmeldingsfout!

In het logboek bb-services worden de volgende uitzonderingen opgenomen:

2017-01-04 22:52:58 -0700 - unsuccessfulAuthentication - org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
    at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:100)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
    at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:87)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at sun.reflect.GeneratedMethodAccessor935.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:282)
    at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:279)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAsPrivileged(Subject.java:549)
    at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314)
    at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)
    at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:46)
    at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:148)
    at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:144)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:143)
    at blackboard.auth.provider.saml.customization.filter.BbSAMLExceptionHandleFilter.doFilterInternal(BbSAMLExceptionHandleFilter.java:30)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    [SNIP]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.opensaml.common.SAMLException: NameID element must be present as part of the Subject in the Response message, please enable it in the IDP configuration
    at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:252)
    at blackboard.auth.provider.saml.customization.consumer.BbSAMLWebSSOProfileConsumerImpl.processAuthenticationResponse(BbSAMLWebSSOProfileConsumerImpl.java:40)
    at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:87)
        ... 214 more

Zoals wordt vermeld in de bovenstaande SAML-uitzondering, ontbreekt het NameID-element uit het Subject in het Response-bericht. Het probleem treedt meestal op wanneer de NameID niet is ingesteld als een Outgoing Claim Type in een Claims Rule voor de Relying Party Trust van de IdP voor ADFS van de instelling of als de Claims Rule voor de NameID niet in de juiste volgorde staat voor Relying Party Trust van de IdP voor ADFS van de instelling, wat weer het ontbrekende NameID-element in het Subject in het Response-bericht tot gevolg heeft.

Voorbeeld: Het element NameID ontbreekt
<Subject>
    <SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
        <SubjectConfirmationData InResponseTo="a22ai8iig0f75ae22hd28748b12da50"
                                 NotOnOrAfter="2017-01-03T05:57:58.234Z"
                                 Recipient="https://yourschool.blackboard.com/auth-saml/saml/SSO"
                                 />
    </SubjectConfirmation>
</Subject>
Voorbeeld: het element NameID is aanwezig
<Subject>
    <NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">testadfs</NameID>
    <SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
        <SubjectConfirmationData InResponseTo="a5903d39if463ea87ieiab5135j9ji"
                                 NotOnOrAfter="2017-01-05T04:33:12.715Z"
                                 Recipient="https://yourschool.blackboard.com/auth-saml/saml/SSO"
                                 />
    </SubjectConfirmation>
</Subject>

Opmerking

Je kunt de Firefox-invoegtoepassing SAML tracer gebruiken om het Subject in het Response-bericht te bekijken.

Oplossing

Er zijn drie methoden om dit probleem op te lossen.

  1. Controleer of de stappen uit de SAML B2-configuratiehandleiding Guide voor ADFS goed zijn uitgevoerd en breng zo nodig wijzigingen aan om een binnenkomende claim voor de Relying Party Trust te transformeren voor hun ADFS IdP:

    1. Selecteer Edit Claims Rule.

    2. Selecteer Add Rule.

    3. Selecteer op de pagina Select Rule Template de optie Transform an Incoming Claim voor de Claim rule template en selecteer daarna Next.

    4. Ga op de pagina Configure Rule naar het veld Claim rule name en typ Transform Email to Name ID.

    5. Stel Incoming claim type in op SamAccountName (moet overeenkomen met de waarde voor Outgoing Claim Type die eerder is gemaakt in de regel Transform Username to NameID).

    6. De waarde voor Outgoing claim type is Name ID.

    7. De waarde voor Outgoing name ID format is Email.

    8. Controleer of Pass through all claim values is geselecteerd selecteer Finish.

    9. Selecteer OK om de regel op te slaan en selecteer nogmaals OK om de toewijzing van de kenmerken te voltooien.

  2. Zorg ervoor dat in de volgorde van de Claims Rules die worden gebruikt voor hun ADFS IdP, er geen optionele regels voorafgaan aan de regel met het NameID-element.

  3. Als je een aangepast kenmerk gebruikt, zorg er dan voor dat het NameID-element zich in de Relying Party Trust bevindt, aangezien Blackboard nog steeds verwacht dat hun ADFS-IDP een NameID-waarde vrijgeeft.

Probleem 6

Wanneer de gebruiker via SAML-verificatie is aangemeld bij Blackboard, probeert hij zich af te melden door op de knop Afmelden aan de linkerkant van de pagina te klikken en vervolgens op de knop Eenmalige aanmelding beëindigen te klikken, een Aanmeldingsfout! wordt onmiddellijk weergegeven.

Sign On Error!
Blackboard Learn is currently unable to log into your account using single sign-on. Contact your administrator for assistance.
For reference, the Error ID is [error ID].

In het logboek bb-services wordt de volgende uitzondering opgenomen:

2017-05-08 15:10:46 -0400 - BbSAMLExceptionHandleFilter Error Id: f3299757-8d4e-4fab-98cf-49cd99f4891e - javax.servlet.ServletException: Incoming SAML message failed security validation
    at org.springframework.security.saml.SAMLLogoutProcessingFilter.processLogout(SAMLLogoutProcessingFilter.java:145)
    at org.springframework.security.saml.SAMLLogoutProcessingFilter.doFilter(SAMLLogoutProcessingFilter.java:104)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    [SNIP]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.opensaml.ws.security.SecurityPolicyException: Validation of request simple signature failed for context issuer
    at org.opensaml.common.binding.security.BaseSAMLSimpleSignatureSecurityPolicyRule.doEvaluate(BaseSAMLSimpleSignatureSecurityPolicyRule.java:139)
    at org.opensaml.common.binding.security.BaseSAMLSimpleSignatureSecurityPolicyRule.evaluate(BaseSAMLSimpleSignatureSecurityPolicyRule.java:103)
    at org.opensaml.ws.security.provider.BasicSecurityPolicy.evaluate(BasicSecurityPolicy.java:51)
    at org.opensaml.ws.message.decoder.BaseMessageDecoder.processSecurityPolicy(BaseMessageDecoder.java:132)
    at org.opensaml.ws.message.decoder.BaseMessageDecoder.decode(BaseMessageDecoder.java:83)
    at org.opensaml.saml2.binding.decoding.BaseSAML2MessageDecoder.decode(BaseSAML2MessageDecoder.java:70)
    at org.springframework.security.saml.processor.SAMLProcessorImpl.retrieveMessage(SAMLProcessorImpl.java:105)
    at org.springframework.security.saml.processor.SAMLProcessorImpl.retrieveMessage(SAMLProcessorImpl.java:172)
    at org.springframework.security.saml.SAMLLogoutProcessingFilter.processLogout(SAMLLogoutProcessingFilter.java:131)
    ... 244 more

De fout treedt op vanwege de instelling Servicetype eenmalig afmelden op de pagina Instellingen voor SAML-verificatie.

Oplossing

De instelling moet worden geconfigureerd in Blackboard en op de ADFS-server.

Voor ADFS als IdP selecteert u alleen de instelling Post en verwijdert u het eindpunt voor de vertrouwenspersoon van de relying party van de Blackboard-instantie op de ADFS-server.

  1. Navigeer in Blackboard naar Admin > Authentication > (providernaam) > SAML-instellingen > servicetype voor één afmelding.

  2. Selecteer Bericht en schakel het selectievakje Omleiden uit.

  3. Ga op de ADFS-server naar de vertrouwensrelatie van de relying party voor je Blackboard-instantie.

  4. Selecteer Properties > Endpoints. Er worden twee eindpunten voor SAML-afmelding vermeld.

  5. Verwijder het eindpunt Redirect. Selecteer Remove Endpoint om het te verwijderen, en kies vervolgens Apply en OK.

Nadat je de bovenstaande wijzigingen hebt aangebracht in Blackboard en de ADFS-server, wordt de afmeldknop Eenmalige aanmelding beëindigen gebruikt om de gebruiker correct af te melden.

Probleem 7

Na het invoeren van de inloggegevens op de ADFS-inlogpagina, verschijnt een aanmeldingsfout! bericht wordt weergegeven wanneer het wordt doorgestuurd naar Blackboard.

In het logboek bb-services wordt de volgende SAML-uitzondering opgenomen:

2017-05-26 07:39:30 -0400 - unsuccessfulAuthentication - org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
        at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:100)
        at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
        at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:87)
        at blackboard.auth.provider.saml.customization.filter.BbSAMLProcessingFilter.attemptAuthentication(BbSAMLProcessingFilter.java:46)
        at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
        at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
        at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
        at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
        at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
        at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
        at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
        at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
        at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
        at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
        at sun.reflect.GeneratedMethodAccessor380.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:282)
        at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:279)
        at java.security.AccessController.doPrivileged(Native Method)
        at javax.security.auth.Subject.doAsPrivileged(Subject.java:549)
        at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314)
        at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)
        at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:46)
        at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:148)
        at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:144)
        at java.security.AccessController.doPrivileged(Native Method)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:143)
        at blackboard.auth.provider.saml.customization.filter.BbSAMLExceptionHandleFilter.doFilterInternal(BbSAMLExceptionHandleFilter.java:37)
    [SNIP]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:745)
Caused by: org.opensaml.common.SAMLException: Response has invalid status code urn:oasis:names:tc:SAML:2.0:status:Responder, status message is null
        at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:113)
        at blackboard.auth.provider.saml.customization.consumer.BbSAMLWebSSOProfileConsumerImpl.processAuthenticationResponse(BbSAMLWebSSOProfileConsumerImpl.java:56)
        at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:87)
        ... 247 more
Oplossing

Er is een optie om het SAML-coderingscertificaat opnieuw te genereren door te navigeren naar System Admin > Building Blocks > Authentication Provider - SAML > Settings > Regenerate Certificate. De Aanmeldingsfout! probleem kan optreden als de knop Certificaat opnieuw genereren is geselecteerd nadat de SP-metagegevens al zijn geüpload naar de vertrouwensrelatie van de relying party voor de Blackboard-site op de ADFS-server. Je kunt dit probleem als volgt oplossen:

  1. Ga naar Systeembeheer > Verificatie > "naam van SAML-provider" > Instellingen voor SAML-verificatie.

  2. Selecteer Genereren naast Metadata serviceprovider om het nieuwe bestand met metagegevens op te slaan.

  3. Open uw ADFS-server en upload de nieuwe SP-metagegevens naar de vertrouwenspersoon van relying party voor uw Blackboard-site.

Opmerking

Als je een nieuw certificaat genereert onder de B2-instellingen, moet je de SAML B2 op Inactief zetten en vervolgens teruggaan naar Geactiveerd om de wijziging door te voeren. Daarna ga je terug naar de instellingen van de provider en genereer je de nieuwe metagegevens om te importeren in de IDP. Als je deze instellingen niet inschakelt, kan het oude certificaat nog steeds worden meegenomen als je nieuwe metagegevens genereert. De IDP wordt niet bijgewerkt en de volgende keer dat Mijn Blackboard opnieuw wordt opgestart, wordt het nieuwe certificaat weergegeven. De SAML-verificatie wordt daardoor verbroken omdat de IDP en het certificaat niet overeenkomen.

Metagegevens voor federatie

Aangezien bij Active Directory Federation Services (ADFS) de metagegevens voor een ADFS-federatie die zich doorgaans in https://[ADFS Server Hostname]/FederationMetadata/2007-06/FederationMetadata.xml bevindt, een element bevatten dat niet compatibel is met SAML 2.0, moeten de metagegevens worden bewerkt om het incompatibele element te verwijderen voordat het wordt geüpload naar de sectie Instellingen voor identiteitsprovider op de pagina SAML-verificatie-instellingen in de GUI van Blackboard. Als de metagegevens met het incompatibele element worden geüpload, treedt er een fout op bij het selecteren van de SAML-aanmeldingskoppeling op de aanmeldingspagina van Blackboard: Metagegevens voor entiteit [entiteit] en rol {} zijn niet gevonden. For reference, the Error ID is [error ID].

En dit is de bijbehorende Java-stacktrace voor de fout-ID in het logboek bb-services:

2016-06-21 11:42:51 -0700 - Metadata for entity https://<Learn Server Hostname>/adfs/ls/ and role {urn:oasis:names:tc:SAML:2.0:metadata}SPSSODescriptor wasn&#39;t found<P><span class="captionText">For reference, the Error ID is c99511ae-1162-4941-b823-3dda19fea157.</span> - org.opensaml.saml2.metadata.provider.MetadataProviderException: Metadata for entity https://ulvsso.laverne.edu/adfs/ls/ and role {urn:oasis:names:tc:SAML:2.0:metadata}SPSSODescriptor wasn't found
    at org.springframework.security.saml.context.SAMLContextProviderImpl.populateLocalEntity(SAMLContextProviderImpl.java:319)
    at org.springframework.security.saml.context.SAMLContextProviderImpl.populateLocalContext(SAMLContextProviderImpl.java:216)
    at org.springframework.security.saml.context.SAMLContextProviderImpl.getLocalAndPeerEntity(SAMLContextProviderImpl.java:126)
    at org.springframework.security.saml.SAMLEntryPoint.commence(SAMLEntryPoint.java:146)
    at org.springframework.security.saml.SAMLEntryPoint.doFilter(SAMLEntryPoint.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at sun.reflect.GeneratedMethodAccessor1652.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
        [SNIP]
Oplossing

Aangezien de standaardmetagegevenslocatie voor een ADFS-federatie https://[ADFS-serverhostname]/FederationMetadata/2007-06/FederationMetadata.xml is:

  1. Download dit bestand en open het in een teksteditor. Verwijder zorgvuldig de sectie die begint met <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> ... </X509Data></KeyInfo> en eindigend op </ds:Signature>

    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">

    <ds:SignedInfo>
      <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
      <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
      <ds:Reference URI="#_43879f32-9a91-4862-bc87-e98b85b51158">
       <ds:Transforms>
        <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
        <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
       </ds:Transforms>
       <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
       <ds:DigestValue>z1H1[SNIP]jaYM=</ds:DigestValue>
      </ds:Reference>
      </ds:SignedInfo>
      <ds:SignatureValue> FVj[SNIP]edrfNKWvsvk5A==
      </ds:SignatureValue>
      <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
       <X509Data>
        <X509Certificate>
        FDdd[SNIP]qTNKdk5F/vf1AocDaX
        </X509Certificate>
       </X509Data>
      </KeyInfo>
    </ds:Signature>
  2. Upload het bijgewerkte XML-bestand met metagegevens in de GUI van Blackboard op de pagina SAML-verificatie-instellingen in de sectie Instellingen voor identiteitsprovider.

  3. Schakelen tussen de SAML-verificatieprovider en SAML B2 inactief/beschikbaar, terwijl de verificatieprovider van de SAML de status 'Actief' heeft.

Belangrijk

Als een instelling SAML-verificatie test op een Blackboard-site en meerdere SAML-verificatieproviders heeft die hetzelfde onderliggende ADFS IdP-metagegevens-XML-bestand op de Blackboard-site delen, moeten de andere SAML-verificatieproviders ook het bijgewerkte XML-bestand met metagegevens hebben geüpload in de GUI van Blackboard op de pagina SAML-verificatie-instellingen in de sectie Instellingen voor identiteitsprovider, zelfs als de andere SAML-verificatieproviders zijn ingesteld op Inactief, zelfs als de andere SAML-verificatieproviders zijn ingesteld op Inactief, maar ook als de andere SAML-verificatieproviders zijn ingesteld op Inactief, moeten ze ook het bijgewerkte XML-bestand met metagegevens uploaden in de GUI van Blackboard op de pagina SAML-verificatie-instellingen in de sectie Instellingen voor identiteitsprovider. De SAML B2 moet vervolgens tussen Inactief/Beschikbaar worden geschakeld, terwijl de SAML-verificatieprovider de status ‘Actief’ heeft, om er zeker van te zijn dat het bijgewerkte XML-bestand met metagegevens in het hele systeem wordt herkend.

Onjuiste methode voor opzoeken van gebruikers

Na het invoeren van de inloggegevens op de ADFS-inlogpagina, wordt de gebruiker omgeleid naar de GUI van Blackboard, maar niet aangemeld bij Blackboard.

Dit is de ENIGE gebeurtenis die voor SAML-verificatie wordt vastgelegd in het logboek bb-services:

2016-10-18 13:03:28 -0600 - userName is null or empty
Oplossing
  1. Meld je aan bij Blackboard als beheerder met de standaard interne verificatie van Blackboard.

  2. Ga naar Systeembeheer > "naam van SAML-verificatieprovider" > Bewerken.

  3. Wijzig de waarde voor Zoekmethode gebruikers van Batch-UID in Gebruikersnaam.

Extra afmeldknop SSO-sessie beëindigen

ADFS probeert een extra knop Eenmalige aanmelding beëindigen toe te voegen aan de knop Alle sessies beëindigen? pagina die wordt weergegeven nadat u eerst de knop Uitloggen rechtsboven in de GUI van Blackboard hebt geselecteerd.

Hiervoor wordt een extra SingleLogoutService toegevoegd aan het bestand met IdP-metagegevens:

<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://your.server.name/adfs/ls/"/>
<SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://your.server.name/adfs/ls/"/>

Aangezien dat een optionele SAML B2 IdP-configuratie is en de handtekening in het omleidingseindpunt niet correct is, treedt er een fout op bij het selecteren van de extra knop Eenmalige aanmelding-sessie beëindigen op de knop Alle sessies beëindigen? pagina: Binnenkomend SAML-bericht is mislukt beveiligingsvalidatie. Validation of request simple signature failed for context issuer. For reference, the error Id is [fout-ID].

Dit is de bijbehorende Java-stacktrace voor de fout-ID in het logboek bb-services:

2016-10-17 16:57:44 -0400 - Incoming SAML message failed security validation Validation of request simple signature failed for context issuer<P><span class="captionText">For reference, the Error ID is 930c7767-8710-475e-8415-2077152280e0.</span> - org.opensaml.ws.security.SecurityPolicyException: Validation of request simple signature failed for context issuer
    at org.opensaml.common.binding.security.BaseSAMLSimpleSignatureSecurityPolicyRule.doEvaluate(BaseSAMLSimpleSignatureSecurityPolicyRule.java:139)
    at org.opensaml.common.binding.security.BaseSAMLSimpleSignatureSecurityPolicyRule.evaluate(BaseSAMLSimpleSignatureSecurityPolicyRule.java:103)
    at org.opensaml.ws.security.provider.BasicSecurityPolicy.evaluate(BasicSecurityPolicy.java:51)
    at org.opensaml.ws.message.decoder.BaseMessageDecoder.processSecurityPolicy(BaseMessageDecoder.java:132)
    at org.opensaml.ws.message.decoder.BaseMessageDecoder.decode(BaseMessageDecoder.java:83)
    at org.opensaml.saml2.binding.decoding.BaseSAML2MessageDecoder.decode(BaseSAML2MessageDecoder.java:70)
    at org.springframework.security.saml.processor.SAMLProcessorImpl.retrieveMessage(SAMLProcessorImpl.java:105)
    at org.springframework.security.saml.processor.SAMLProcessorImpl.retrieveMessage(SAMLProcessorImpl.java:172)
    at org.springframework.security.saml.SAMLLogoutProcessingFilter.processLogout(SAMLLogoutProcessingFilter.java:131)
    at org.springframework.security.saml.SAMLLogoutProcessingFilter.doFilter(SAMLLogoutProcessingFilter.java:104)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at sun.reflect.GeneratedMethodAccessor1652.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
        [SNIP]
Oplossing
  1. Open de ADFS-server en ga naar de Relying Party Trust voor de Blackboard-instantie.

  2. Selecteer het tabblad Properties > Endpoints.

  3. Op het tabblad Endpoints staan twee SAML Logout Endpoints.

  4. Verwijder het eindpunt Redirect.

  5. Selecteer Remove Endpoint om het te verwijderen, en kies vervolgens Apply en OK.

Na het verwijderen van het eindpunt Redirect, werkt de knop SSO-sessie beëindigen zonder problemen bij het afmelden van de gebruiker.

Toepassingslogboeken inzien met Logboeken

Als je een probleem met ADFS SAML-verificatie wilt oplossen, kan het ook nodig zijn dat een instelling de toepassingslogboeken van ADFS bekijkt in Logboeken op hun ADFS-server om een beter beeld te krijgen. Dit is met name handig wanneer het SAML-antwoord van de ADFS-server een RequestDenied-status heeft zoals hieronder wordt aangegeven:

<samlp:Status>
    <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Responder">
        <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:RequestDenied" />
    </samlp:StatusCode>
</samlp:Status>

Opmerking

Het SAML-antwoord kan worden bekeken met de Firefox-invoegtoepassing SAML tracer.

De status Verzoek geweigerd in een antwoord geeft meestal aan dat er een probleem is opgetreden wanneer de IdP (ADFS) probeerde het antwoord te begrijpen en het resultaat te verwerken dat de SP (Blackboard) had opgegeven.

Ga als volgt te werk om de toepassingslogboeken van ADFS met Logboeken te bekijken:

  1. Open Logboeken op de ADFS-server.

  2. Selecteer Logboeken voor analyseren en foutopsporing weergeven in het menu Beeld.

  3. Navigeer in de consolestructuur naar Logboeken Toepassingen en Services > AD FS Tracing > Debug.

Azure Active Directory

Azure AD is de Cloudgebaseerde directory- en identiteitsbeheerService van Microsoft (MS).

Eerste deel van e-mailadres versturen

Als een instelling Azure AD gebruikt als hun IdP en alleen het eerste deel van de Azure AD-e-mailgebruikersnaam wil gebruiken voor de Blackboard-gebruikersnaam, kunnen ze hun Azure AD IdP configureren om de speciale functie ExtractMailPrefix() te gebruiken om het domeinachtervoegsel uit het e-mailbericht of de principalnaam van de gebruiker te verwijderen, waardoor alleen het eerste deel van de gebruikersnaam wordt doorgegeven (bijvoorbeeld 'joesmith' in plaats van joesmith@example.com).

Als de Blackboard-Externe gebruikers-IDurn:oid:1.3.6.1.4.1.5923.1.1.1.6 is, ziet de instelling Eigenschap voor de Azure IdP er als volgt uit:

Attribute Name:        urn:oid:1.3.6.1.4.1.5923.1.1.1.6
Attribute Value:    ExtractMailPrefix()
Mail:            user.userprincipalname

Dus met het voorbeeld joesmith@example.com e-mailgebruikersnaam zou deze als volgt worden doorgegeven in de SAML-assertie van de Azure IdP naar Blackboard:

<Attribute Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.6">
    <AttributeValue>joesmith</AttributeValue>

Aanvullende informatie over het gebruik van de functie ExtractMailPrefix() is beschikbaar op de documentatiepagina MS Azure.

Certificaat bijgewerkt door IdP van Azure AD

Na het invoeren van de aanmeldingsgegevens op de MS Azure AD-aanmeldingspagina, verschijnt een aanmeldingsfout! kan worden weergegeven nadat deze is omgeleid naar de GUI van Blackboard.

In het logboek bb-services wordt de volgende uitzondering opgenomen:

2016-10-13 12:03:23 +0800 - unsuccessfulAuthentication - org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
 at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:100)
 at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
 at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:87)
 at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
 at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
 at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
 at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
 at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
 at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
 at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
 at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
 at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
 at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
 at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
 at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
 at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
 at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
 at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
 at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
 at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
 at sun.reflect.GeneratedMethodAccessor854.invoke(Unknown Source)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 at java.lang.reflect.Method.invoke(Method.java:498)
 at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:282)
 at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:279)
 at java.security.AccessController.doPrivileged(Native Method)
 at javax.security.auth.Subject.doAsPrivileged(Subject.java:549)
 at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314)
 at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)
 at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:46)
 at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:148)
 at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:144)
 at java.security.AccessController.doPrivileged(Native Method)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:143)
 at blackboard.auth.provider.saml.customization.filter.BbSAMLExceptionHandleFilter.doFilterInternal(BbSAMLExceptionHandleFilter.java:30)
 [SNIP]
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
 at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
 at java.lang.Thread.run(Thread.java:745)
Caused by: org.opensaml.common.SAMLException: Response doesn't have any valid assertion which would pass subject validation
 at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:229)
 at blackboard.auth.provider.saml.customization.consumer.BbSAMLWebSSOProfileConsumerImpl.processAuthenticationResponse(BbSAMLWebSSOProfileConsumerImpl.java:40)
 at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:87)
 ... 230 more
Caused by: org.opensaml.xml.validation.ValidationException: Signature is not trusted or invalid
 at org.springframework.security.saml.websso.AbstractProfileBase.verifySignature(AbstractProfileBase.java:272)
 at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.verifyAssertionSignature(WebSSOProfileConsumerImpl.java:419)
 at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.verifyAssertion(WebSSOProfileConsumerImpl.java:292)
 at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:214)
 ... 232 more

Dit wordt veroorzaakt doordat de MS Azure AD IdP het certificaat bijwerkt, maar de metagegevens-XML die door de Blackboard SP wordt gebruikt, niet wordt aangepast om het nieuwe certificaat weer te geven.

Oplossing
  • Het nieuwe metagegevens-XML-bestand met het nieuwe certificaat moet worden bijgewerkt op de pagina SAML-instellingen in de GUI van Blackboard voor de verificatieprovider.

  • De SAML B2- en de verificatieprovider moeten vervolgens worden geschakeld tussen Inactief/Beschikbaar, terwijl de SAML-verificatieprovider de status ‘Actief’ heeft, om ervoor te zorgen dat de bijgewerkte metagegevens met het nieuwe certificaat worden toegepast..

  • Als een Blackboard-site meerdere verificatieproviders heeft die hetzelfde onderliggende certificaat delen voor dezelfde onderliggende IdP-entiteits-ID, moeten AL deze verificatieproviders worden bijgewerkt.

Door IdP gestarte eenmalige aanmelding

Als een gebruiker zich eerst aanmeldt bij de gebruikersportal en vervolgens de app voor de Blackboard-site selecteert, wordt een nieuw browsertabblad geopend met het volgende bericht: De opgegeven bron is niet gevonden of je hebt geen machtiging om de bron te openen.

Deze overeenkomende gebeurtenissen voor SAML worden vastgelegd in het logboek stdout-stderr:

INFO   | jvm 1    | 2016/08/16 10:49:22 | - /saml/SSO at position 1 of 10 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
INFO   | jvm 1    | 2016/08/16 10:49:22 | - HttpSession returned null object for SPRING_SECURITY_CONTEXT
INFO   | jvm 1    | 2016/08/16 10:49:22 | - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@58c53845. A new one will be created.
INFO   | jvm 1    | 2016/08/16 10:49:22 | - /saml/SSO at position 2 of 10 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
INFO   | jvm 1    | 2016/08/16 10:49:22 | - /saml/SSO at position 3 of 10 in additional filter chain; firing Filter: 'HeaderWriterFilter'
INFO   | jvm 1    | 2016/08/16 10:49:22 | - /saml/SSO at position 4 of 10 in additional filter chain; firing Filter: 'FilterChainProxy'
INFO   | jvm 1    | 2016/08/16 10:49:22 | - Checking match of request : '/saml/sso'; against '/saml/login/**'
INFO   | jvm 1    | 2016/08/16 10:49:22 | - Checking match of request : '/saml/sso'; against '/saml/logout/**'
INFO   | jvm 1    | 2016/08/16 10:49:22 | - Checking match of request : '/saml/sso'; against '/saml/bbsamllogout/**'
INFO   | jvm 1    | 2016/08/16 10:49:22 | - Checking match of request : '/saml/sso'; against '/saml/sso/**'
INFO   | jvm 1    | 2016/08/16 10:49:22 | - /saml/SSO at position 1 of 1 in additional filter chain; firing Filter: 'SAMLProcessingFilter'
INFO   | jvm 1    | 2016/08/16 10:49:22 | - Forwarding to /
INFO   | jvm 1    | 2016/08/16 10:49:22 | - DispatcherServlet with name 'saml' processing POST request for [/auth-saml/saml/SSO]
INFO   | jvm 1    | 2016/08/16 10:49:22 | - No mapping found for HTTP request with URI [/auth-saml/saml/SSO] in DispatcherServlet with name 'saml'
INFO   | jvm 1    | 2016/08/16 10:49:22 | - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
INFO   | jvm 1    | 2016/08/16 10:49:22 | - Successfully completed request
INFO   | jvm 1    | 2016/08/16 10:49:22 | - Skip invoking on
INFO   | jvm 1    | 2016/08/16 10:49:22 | - SecurityContextHolder now cleared, as request processing completed

De sectie Instellingen voor serviceproviders van de pagina SAML-verificatie-instellingen is gewijzigd en de optie Automatische Eenmalige aanmelding inschakelen moet zijn ingeschakeld om een gebruiker toegang te geven tot Blackboard vanuit de portal. Als de optie is ingeschakeld, wordt de ACS URL ook gewijzigd en uitgebreid met een alias.

Fout door onjuist document

Na het invoeren van de inloggegevens op de inlogpagina van de SAML-verificatieprovider, verschijnt er een aanmeldingsfout! kan worden weergegeven nadat deze is omgeleid naar de GUI van Blackboard.

In het logboek bb-services worden de volgende gebeurtenissen opgenomen: DOMException en WRONG_DOCUMENT_ERR:

2016-11-18 12:27:31 -0600 - WRONG_DOCUMENT_ERR: A node is used in a different document than the one that created it.<P><span class="captionText">For reference, the Error ID is 86ebb81d-d3a3-4da5-95ab-1c94505f4281.</span> - org.w3c.dom.DOMException: WRONG_DOCUMENT_ERR: A node is used in a different document than the one that created it.
    at org.apache.xerces.dom.ParentNode.internalInsertBefore(Unknown Source)
    at org.apache.xerces.dom.ParentNode.insertBefore(Unknown Source)
    at org.apache.xerces.dom.NodeImpl.appendChild(Unknown Source)
    at org.opensaml.xml.encryption.Decrypter.parseInputStream(Decrypter.java:832)
    at org.opensaml.xml.encryption.Decrypter.decryptDataToDOM(Decrypter.java:610)
    at org.opensaml.xml.encryption.Decrypter.decryptUsingResolvedEncryptedKey(Decrypter.java:795)
    at org.opensaml.xml.encryption.Decrypter.decryptDataToDOM(Decrypter.java:535)
    at org.opensaml.xml.encryption.Decrypter.decryptDataToList(Decrypter.java:453)
    at org.opensaml.xml.encryption.Decrypter.decryptData(Decrypter.java:414)
    at org.opensaml.saml2.encryption.Decrypter.decryptData(Decrypter.java:141)
    at org.opensaml.saml2.encryption.Decrypter.decrypt(Decrypter.java:69)
    at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:199)
    at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:82)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
    at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:87)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at sun.reflect.GeneratedMethodAccessor1209.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:277)
    at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:274)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAsPrivileged(Subject.java:549)
    at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:309)
    at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:249)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
    at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:55)
    at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:191)
    at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:187)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:186)
    at blackboard.platform.servlet.DevNonceFilter.doFilter(DevNonceFilter.java:68)
    [SNIP]

De reden dat het probleem zich voordoet, is dat een ander B2/Project de systeemeigenschap javax.xml.parsers.DocumentBuilderFactory waarde heeft gewijzigd van org.apache.xerces.jaxp.DocumentBuilderFactoryImpl in com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl.

Tijdelijke oplossing

Totdat er een correctie beschikbaar komt, zijn dit de tijdelijke oplossingen:

  1. Bb-services opnieuw starten op elk knooppunt.

  2. Codering van SAML-antwoorden aan de kant van de IdP uitschakelen. Aangezien de communicatie volledig verloopt via SSL, heeft dit geen gevolgen voor de beveiliging van de verificatie.

Geen optie om SAML toe te voegen aan providervolgorde

Bij het configureren van SAML-verificatie kan een instelling merken dat er geen optie is om een SAML-verificatieprovider toe te voegen in de sectie Providerorder in de GUI van Blackboard wanneer ze naar Building Blocks > System Admin: Authentication > Provider Order navigeert.

De reden waarom er geen optie is om een SAML-verificatieprovider toe te voegen aan Volgorde van providers is dat providers die op basis van omleiding werken, zoals CAS en SAML, verificatie overdragen aan de externe verificatiebron. Deze worden niet vermeld bij Volgorde van providers aangezien ze worden beschouwd als de gezaghebbende bron voor verificatie en ze hun eigen verificatiefouten afhandelen.

SAML-verbinding testen

Er is een optie om de verbinding voor een SAML-provider te testen in de sectie Verificatie in de GUI van Blackboard. Tijdens de verbindingstest worden de volgende items gecontroleerd:

  • IdP-metagegevens parseren

  • Verbinden met IdP

  • SAML-antwoord ontvangen

  • SAML-antwoord parseren

  • Overeenkomst externe gebruikers-ID

  • Aanmelden bij Blackboard

Ga als volgt te werk om de verbinding voor een SAML-verificatieprovider te testen:

  1. Meld je aan bij Blackboard als beheerder.

  2. Navigeer naar Building Blocks > systeembeheerder: verificatie > 'SAML-providernaam' > testverbinding.

  3. Voer de aanmeldingsreferenties voor de IdP in als daarom wordt gevraagd.

De functie Verbinding testen kan om meerdere redenen worden gebruikt in plaats van het handmatig inschakelen van logboekregistratie voor SAML-foutopsporing in Blackboard.

De waarde Identity Provider Entity ID die wordt weergegeven op de uitvoerpagina Verbinding testen wordt opgehaald uit het element Verlener in de SAML POST van de IdP naar Blackboard nadat de gebruiker is geverifieerd:

<Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">http://bbpdcsi-adfs1.bbpdcsi.local/a...services/trust</Issuer>

De waarden SAML Attribute die worden weergegeven op de uitvoerpagina Verbinding testen in de sectie SAML-reactie worden opgehaald uit de elementen Onderwerp en AttributeStatement in de SAML POST van de IdP naar Blackboard nadat de gebruiker is geverifieerd:

<Subject>
    <NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">luke.skywalker</NameID>
    [SNIP]
</Subject>
<AttributeStatement>
    <Attribute Name="SamAccountName">
        <AttributeValue>luke.skywalker</AttributeValue>
    </Attribute>
    <Attribute Name="urn:oid:2.5.4.42">
        <AttributeValue>Luke</AttributeValue>
    </Attribute>
    <Attribute Name="urn:oid:2.5.4.4">
        <AttributeValue>Skywalker</AttributeValue>
    </Attribute>
</AttributeStatement>

Een SAML-verificatieprovider en IdP maken voor testdoeleinden

Gebruik de onderstaande stappen om een IdP (identiteitsprovider) te maken met de gratis oplossing voor SSO-verificatie van Centrify.

Die IdP kan vervolgens worden geconfigureerd als de SAML-verificatieprovider in een Blackboard Service Provider (SP):

Aanbieder van Blackboard-services
  1. Meld je als beheerder aan bij de GUI van Blackboard en navigeer naar Systeembeheerder > verificatie.

  2. Selecteer Provider maken > SAML.

  3. Geef waarden op voor de volgende instellingen:

    • Naam > SAML of een andere naam.

    • Verificatieprovider > Inactief (voorlopig).

    • Zoekmethode gebruikers > Gebruikersnaam

    • Beperken op hostnaam > Deze provider gebruiken voor alle hostnamen

    • Koppelingstekst > SAML Centrify-aanmelding

  4. Selecteer Opslaan en configureren.

  5. In het veld Entity ID kun je elke gewenste waarde invoeren (als je de ID later wijzigt, moet je de bijgewerkte metagegevens voor de serviceprovider wel doorgeven aan de identiteitsprovider). Dit kan door eenvoudigweg door de ACS URL te kopiëren en plakken.

  6. Selecteer Genereren onder Metadata serviceprovider en sla het bestand op je computer op.

  7. Het wordt aangeraden om onder Gegevensbron een nieuwe gegevensbron te maken voor deze serviceprovider met de naam CENTRIFY, of anders SYSTEEM of een andere naam.

  8. Vink het vakje JIT-inrichting inschakelen aan, zodat er automatisch een account wordt gemaakt als er wordt geprobeerd om aan te melden via deze SAML-verificatieprovider en de gebruiker niet bestaat. Als JIT Provisioning niet is geselecteerd, moet de gebruiker in Blackboard handmatig worden aangemaakt.

  9. Selecteer in de lijst Compatibele gegevensbronnen de gegevensbronnen waarmee deze verificatieprovider compatibel moet zijn.

  10. Selecteer Identiteitsprovider aanwijzen voor Type van de identiteitsprovider.

  11. Sla Metadata identiteitsprovider nu even over. Je gaat het bestand uploaden nadat dit is gemaakt in de volgende sectie.

  12. Geef in de sectie SAML-kenmerken in kaart brengenNameID op voor Externe gebruikers-ID.

  13. Selecteer Verzenden.

Identiteitsprovider van Centrify
  1. Ga naar de Centrify-website en selecteer Nu starten.

  2. Voer de aanmeldingsgegevens in en selecteer Start Now.

  3. Je krijgt een welkomstmail met je beheerdersreferenties. Gebruik ze om in te loggen op https://Cloud.centrify.com.

  4. Selecteer Skip in het venster Welcome to Centrify Identify Service.

  5. Ga naar het tabblad Apps boven aan de pagina en selecteer de knop Add Web Apps.

  6. Scrol omlaag op het tabblad Custom en selecteer de knop Add voor SAML. Selecteer Ja.

  7. Selecteer Close onder aan het venster Add Web Apps.

  8. Ga naar het tabblad Apps. Selecteer in de sectie Toepassingsinstellingen de knop SP-metagegevens uploaden en upload het bestand dat is gemaakt in stap 6 van de sectie Blackboard SP.

  9. Het veld Assertion Consumer Service URL moet automatisch worden ingevuld nadat de SP-metagegevens zijn geüpload.

  10. Schakel Bewering versleutelen uit. Hierdoor kunnen de attributen die uit de IdP worden vrijgegeven en naar Blackboard worden verzonden, worden bekeken met behulp van de Firefox-browser SAML tracer Add-on of Chrome SAML Message Decoder. Aangezien de communicatie volledig verloopt via SSL, heeft dit geen gevolgen voor de beveiliging van de verificatie.

  11. Scrol omlaag en selecteer Download Identity Provider SAML Metadata. Bewaar het bestand op je computer.

  12. Selecteer Save en ga naar de volgende sectie.

  13. Voer een waarde in voor Description. Selecteer Save en ga naar de volgende sectie.

  14. Selecteer Everybody en System Administrator in de sectie User Acces. Selecteer Opslaan.

  15. Laat de sectie Policy ongewijzigd.

  16. Controleer in de sectie Accounttoewijzing of userprincipalname is ingevoerd voor de veldnaam Directoryservice.

  17. Voeg in de sectie Advanced de volgende regel toe aan het einde van het script dat wordt gebruikt om een SAML-bevestiging te genereren voor de toepassing:

    Het volledige script ziet er dan zo uit:

    setIssuer(Issuer);
    setSubjectName(UserIdentifier);
    setAudience('https://YourLearnServer.blackboard.c...saml/saml/SSO');
    setRecipient(ServiceUrl);
    setHttpDestination(ServiceUrl);
    setSignatureType('Assertion');
    setNameFormat('emailaddress');
    setAttribute("NameID", LoginUser.Get("userprincipalname"));

    Hierdoor kan de Centrify-IdP een AttributeStatement vrijgeven met de User ID in de SAML POST.

    Voorbeeld:

    <AttributeStatement>
        <Attribute Name="NameID"
                   NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic"
                   >
            <AttributeValue>luke.skywalker@blackboard.com.47</AttributeValue>
        </Attribute>
    </AttributeStatement>
  18. Selecteer Opslaan.

  19. De overige secties kunnen ongewijzigd blijven (App Gateway, Changelog en Workflow).

  20. Controleer op het tabblad Apps of de SAML-app automatisch is geïmplementeerd.

  21. Selecteer Add Users op het tabblad Users, voer de accountgegevens voor een gebruiker in en selecteer Create User.

  22. Meld je als beheerder opnieuw aan bij de GUI van Blackboard, navigeer naar System Admin > Authentication > SAML Authentication Provider Name > SAML Settings > Identity Provider Settings, upload het IdP-metagegevensbestand dat in stap 13 op je bureaublad is opgeslagen en selecteer Verzenden.

De Centrify IdP-gebruiker die is gemaakt, kan zich nu via SAML aanmelden bij Blackboard door die authenticatieprovider te selecteren op de inlogpagina en zich af te melden bij Blackboard met behulp van de extra Eenmalige aanmelding-sessie afmeldknop op de knop Alle sessies beëindigen? pagina die wordt weergegeven nadat u de knop Afmelden in de rechterbovenhoek van Blackboard hebt geselecteerd.

Tekst wijzigen op afmeldingspagina SSO-sessie beëindigen

Een instelling kan desgewenst de tekst op de afmeldingspagina SSO-sessie beëindigen aanpassen. Dit kan door het taalpakket te bewerken:

  1. Open het bestand met het taalpakket.

  2. Navigeer naar auth-provider-saml/src/main/webapp/WEB-INF/bundles/bb-manifest-en_US.properties.

  3. Pas deze berichtsleutels aan:

    saml.single.logout.warning.conent.description // the first line
    saml.single.logout.warning.conent.recommend // second line
    saml.single.logout.warning.endsso.title // third line
    saml.single.logout.warning.endsso.button // the button
    saml.single.logout.warning.backtolearn // the cancel button

Leid gebruikers om naar de IdP-inlogpagina

De standaard aanmeldingspagina van Blackboard bevat gebruikersnaam- en wachtwoordvelden voor de standaardverificatieprovider van Learn. Wanneer u SAML-verificatie inschakelt, verschijnt een klein berichtje 'Aanmelden met...' link voor SAML wordt onder aan deze pagina weergegeven, dus je kunt gebruikers automatisch omleiden naar de verificatieserver van de IdP wanneer ze de aanmeldingspagina van Blackboard openen.

Een optie om dit te bereiken is om naar System Admin > Authentication te navigeren en de standaard Learn Internal-authenticatie in te stellen op Inactief, wat betekent dat er geen inlogpagina meer wordt weergegeven en de gebruiker onmiddellijk wordt doorgestuurd naar de SAML-login. Het probleem met deze optie is dat de standaard-URL voor aanmelding wordt genegeerd, waardoor alleen SAML-gebruikers zich kunnen aanmelden.

Om dit probleem te voorkomen en bijna hetzelfde resultaat te bieden, kun je een aangepaste aanmeldingspagina gebruiken. Gebruikers worden omgeleid naar de aanmeldingspagina van de IdP van de SAML-verificatieprovider, maar de standaardkoppeling voor aanmelden is ook beschikbaar.

  1. Zorg ervoor dat de interne verificatie van Learn actief is

  2. Kopieer op de standaardaanmeldingspagina de locatie van de provideromleiding, bijvoorbeeld Aanmelden met behulp van... SAML. Klik met de rechtermuisknop op de koppeling en selecteer Koppelingslocatie kopiëren.

  3. Navigeer naar Systeembeheerder > community's > merken en thema's > Aanmeldingspagina aanpassen.

  4. Selecteer Downloaden naast Standaardaanmeldingspagina om het standaard JSP-bestand voor aanmelden te downloaden.

  5. Open het JSP-bestand met een teksteditor. Voeg de volgende voorbeeld-HTML toe aan het JSP-bestand voor aanmelding en vervang de URL-tekst door de URL die in stap 2 is gekopieerd.

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    <html>
    <head>
    <title>Blackboard Learn - Redirect</title>
    <meta http-equiv="REFRESH" content="0;url=https://URL_Goes_Here"></HEAD>
    <BODY style="font-family: arial,sans-serif;font-size: small; color: grey; padding: 1em; ">
    Redirecting... <a style="color:grey" href="https://URL_Goes_Here">Go to login page</a> if you are not automatically redirected.
    </BODY>
    </HTML>
  6. Ga opnieuw naar Aanmeldingspagina aanpassen in Learn. Selecteer Aangepaste pagina gebruiken en upload het bijgewerkte JSP-aanmeldingsbestand.

  7. Selecteer na het aanbrengen van de wijzigingen Voorbeeld op de pagina Aanmeldingspagina aanpassen om te controleren of de omleiding goed werkt.

Gebruikers die naar de hoofd-URL gaan, worden nu omgeleid naar de aanmeldingspagina voor de SAML-verificatieprovider. Beheerders kunnen zich nog steeds aanmelden met de interne verificatie van Learn via de standaard aanmeldingspagina: /webapps/login/?action=default_login of/webapps/login/login.jsp).