Skip to main content

Problemas comuns com a Autenticação SAML

Esta página apresenta uma visão geral do Building Block Security Assertion Markup Language (SAML) 2.0 junto com questões comuns de acesso único (SSO) e técnicas de resolução de problemas para o provedor de autenticação SAML.

Importante

Se, por qualquer motivo, um arquivo XML de metadados do IdP atualizado/novo for carregado na GUI do Blackboard na página Configurações de autenticação SAML na seção Configurações do provedor de identidade para um provedor de autenticação SAML, o SAML B2 e esse provedor de autenticação SAML também devem ser alternados como Inativo/Disponível, enquanto o provedor de autenticação SAML estiver no status "Ativo", para garantir que todos os metadados do IdP armazenados em cache sejam apagados e que os metadados do IdP atualizados sejam totalmente utilizados.

Principais termos

Os seguintes termos e abreviações são usados em todo este guia:

  • SAML: Linguagem de marcação de asserção de segurança

  • IdP: Provedor de identidade

  • SP: Provedor de serviços

  • ADFS: Serviços de Federação do Active Directory

  • GUI: Interface gráfica do usuário. No contexto do Blackboard, isso significa trabalhar dentro do software.

Editar definições de configuração do SAML

Para ajudar a solucionar problemas de autenticação SAML, o Building Block SAML foi atualizado na versão 3200.2.0 para incluir estas opções e definições de configuração:

  • Definir o limite de idade da sessão SAML

  • Escolher um tipo de algoritmo de assinatura

  • Gerar novamente os certificados

  • Alterar o valor de ResponseSkew

Erros e exceções

Erros/exceções relacionados a SAML são capturados nos seguintes registros:

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

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

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

Esses registros devem sempre ser pesquisados ao investigar um problema de autenticação SAML relatado.

Rastreador SAML

Com as iterações de solução de problemas de autenticação SAML 2.0, em algum momento pode ser necessário confirmar/visualizar os atributos que estão realmente sendo liberados do IdP e enviados ao Blackboard durante o processo de autenticação. Se os atributos do IdP NÃO estiverem criptografados na resposta SAML, o Complemento rastreador de SAML do navegador Firefox ou o Decodificador de mensagens SAML do Chrome poderá ser usado para visualizar os atributos.

Atributo não mapeado adequadamente

Se o atributo que contém o userName não estiver mapeado corretamente conforme especificado no campo código de usuário remoto na seção Mapear atributos SAML na página Configurações de autenticação SAML na GUI do Bb, o seguinte evento será registrado no registro bb-serviços ao tentar acessar no Bb por meio da autenticação SAML:

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

Um Erro de acesso! mensagem exibida no navegador: No momento, a Blackboard não consegue acessar em sua conta usando o acesso único. Entre em contato com o administrador para obter assistência.

Uma imagem de uma mensagem de erro de acesso exibida no navegador informando que a Blackboard não consegue acessar em sua conta usando o canto único. Entre em contato com o administrador para obter assistência.

Uma entrada de Falha de autenticação aparece no registro do 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]
Resolução

Você tem duas opções para resolver o problema. Primeiro, clique na opção Criar contas se elas não existirem no sistema na página Configurações de autenticação SAML na GUI do Blackboard. Como alternativa, você pode tentar visualizar o valor dos atributos liberados pelo IdP via rastreador SAML ou Registro de depuração se os atributos NÃO estiverem criptografados:

<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>

e mapeie o Nome do atributo que tem o AttributeValue desejado para a ID de usuário remoto na página Configurações de autenticação SAML na GUI do Blackboard.

Fonte de dados compatível não selecionada

Os usuários não poderão acessar no Blackboard por meio da autenticação SAML se a Fonte de dados para os usuários não estiver selecionada na seção Configurações do provedor de serviços > fontes de dados compatíveis na página Configurações de autenticação SAML na GUI do Blackboard. O seguinte evento será registrado no registro Bb-serviços ao tentar acessar no Blackboard por meio da autenticação SAML:

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

A mensagem Erro ao efetuar acesso! aparecerá no navegador, bem como Falha de autenticação no registro do 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]
Resolução
  1. Obter o nome de usuário para o usuário que não consegue acessar.

  2. Na GUI do Blackboard, navegue até Administrador do sistema > Usuários e procure o usuário.

  3. Copie a Chave da fonte de dados do usuário.

  4. Navegue para Administração do sistema > Autenticação > "Nome do provedor" > Configurações de SAML > Fontes de dados compatíveis.

  5. Coloque uma marca de seleção ao lado daquela Fonte de dados na coluna Nome e selecione Enviar.

Mensagem de erro "O URL fornecido não está bem formado"

Se o OneLogin estiver configurado como o IdP para o provedor de autenticação SAML no Blackboard, um erro Fornecido URL não está bem formado poderá ser exibido na página após inserir as credenciais do OneLogin ao tentar acessar no Blackboard.

Com o seguinte exibido no bb-services-log:

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
Resolução
  1. Ligue o rastreador SAML do navegador Firefox e replique o problema de acesso.

  2. Verifique o início do evento POST SAML:

    <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. Para a linha 1 com a Resposta, observe que Destino= é definido somente para o destinatário.

  4. Peça para o cliente acessar a seção Configuração do seu IdP do OneAcesso.

  5. Verifique se o campo Destinatário está em branco.

  6. Copie o valor do URL do ACS (consumidor), cole-o no campo Destinatário e selecione Salvar.

Cenários de problema de IdP/SP

  1. Se aparecer um erro depois de você ter sido redirecionado à página de acesso do IdP, os metadados do IdP poderão ser inválidos.

  2. Se aparecer um erro depois de você acessar na página do IdP, os motivos poderão ser:

    1. O mapeamento de atributos entre o SP e o IdP está incorreto, ou o IdP não retornou um código de usuário remoto válido.

    2. A resposta SAML do IdP não foi validada pelo SP. Isso pode ter sido causado por:

      • O IdP assina a resposta SAML com um certificado que não é emitido por uma autoridade de certificação válida, e o repositório de chaves do SP não contém esse certificado.

      • O relógio do sistema do SP está incorreto.

Serviços de Federação do Active Directory (ADFS)

Os nomes dos atributos diferenciam maiúsculas de minúsculas na seção Mapear atributos SAML na página Configurações de autenticação SAML na GUI do Blackboard. Portanto, se o ID de usuário remoto tiver sAMAccountName para o Nome do atributo na página de configurações e o POST SAML real do IdP tiver isso para o Nome do atributo na AttributeStatement:

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

O usuário não poderá acessar. O valor do nome do atributo código de usuário remoto na página Configurações de autenticação SAML precisaria ser alterado de sAMAccountName para SamAccountName.

Aviso de "Recurso não encontrado" ou "Erro ao efetuar acesso!"

Esta seção contém alguns dos problemas comuns que podem impedir que um usuário acesse o sistema no Blackboard por meio da autenticação SAML com o ADFS quando O recurso especificado não foi encontrado ou você não tem permissão para acessá-lo ou Erro de acesso! mensagem é exibida na GUI do Blackboard.

Problema nº 1

Depois de inserir as credenciais de acesso na página de acesso do ADFS, um erro pode ser exibido após ser redirecionado para a GUI do Blackboard: O recurso especificado não foi encontrado ou você não tem permissão para acessá-lo.

Mensagem de erro Um recurso especificado não foi encontrado

Com uma mensagem correspondente no registro stdout-stderr:

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'

O problema ocorre porque o método noHandlerFound() é usado no código DispatcherServlet.java e não é capaz de localizar/mapear a solicitação de SSO HTTP.

/**
 * 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);
 }
}
Resolução

Isso geralmente ocorre porque o código da entidade para a controladora de armazenamento configurada na GUI do Blackboard está incorreto. Isso pode ser resolvido acessando Administração do sistema > Autenticação > Configurações de autenticação SAML > Configurações do provedor de serviços e atualizando a ID da entidade. Para o ADFS, a configuração padrão para a ID da entidade seria https://[Blackboard Server Hostname]/auth-saml/saml/Acesso único.

Nota

Se uma escola alterar seu URL do https://school.blackboard.com padrão para https://their.school.edu, o ID da entidade na GUI do Blackboard na página Configurações de autenticação SAML deverá ser atualizado para https://their.school.edu/auth-saml/saml/Acesso único.

Problema nº 2

Depois de inserir as credenciais de acesso na página de acesso do ADFS, um erro pode ser exibido após ser redirecionado para a GUI do Blackboard: O recurso especificado não foi encontrado ou você não tem permissão para acessá-lo.

Com esta mensagem correspondente no registro stdout-stderr:

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'

E esta mensagem no registro catalina:

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

E esta mensagem exibida no registro 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

O problema ocorre porque, por padrão, o ADFS criptografa os atributos que envia usando o AES-256 e o tempo de execução do Java usado pelo Blackboard não é compatível com o AES-256 pronto para uso.

Resolução

Uma opção de resolução universal é abrir um PowerShell no servidor ADFS e definir a terceira parte confiável criada para o Blackboard para enviar os atributos como não criptografados. Uma vez que a comunicação como um todo é por SSL, isso não reduzirá a segurança da autenticação. Ele também facilita a depuração dos problemas, uma vez que os atributos podem ser visualizados com ferramentas de depuração, como o complemento rastreador SAML do navegador Firefox e não é necessário reiniciar o sistema do Blackboard. Para definir a terceira parte confiável criada para o Blackboard para enviar os atributos como não criptografados, abra um PowerShell e execute o seguinte comando, substituindo TargetName pelo nome da Confiança de Terceira Parte Confiável que está no Console de Gerenciamento do ADFS em Relações de Confiança > Relações de Confiança de Terceira Parte Confiável.

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

Após essa alteração, o serviço ADFS precisará ser reiniciado com o comando: Restart-Service ADFSSRV

Problema nº 3

Depois de inserir as credenciais de acesso na página de acesso do ADFS, um erro pode ser exibido após ser redirecionado para a GUI do Blackboard: O recurso especificado não foi encontrado ou você não tem permissão para acessá-lo ou Erro de acesso!

Com qualquer uma das opções, estes eventos relacionados SAML com correspondências similares aparecem no registro 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

Ou estas exceções SAML similares no registro 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

O problema ocorre quando o servidor ADFS e o servidor do aplicativo Blackboard têm um desvio de tempo próximo ou além do padrão de 60 segundos.

Resolução

Existem duas opções para resolver o problema:

  • Sincronizar manualmente os relógios dos servidores do aplicativo Blackboard e do servidor ADFS. Para o Blackboard, a hora atual e o fuso horário do servidor podem ser visualizados em um navegador da web adicionando /webapps/portal/healthCheck ao final de um URL do Blackboard.

    Exemplo: 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

    Nota

    Uma instituição pode usar o URL acima para comparar o fuso horário e o relógio do sistema Blackboard com os do servidor ADFS e, em seguida, ajustar esses itens conforme necessário no servidor ADFS para que estejam sincronizados com o site da Blackboard.

Problema nº 4

Depois de inserir as credenciais de acesso na página de acesso do ADFS, um erro pode ser exibido após ser redirecionado para a GUI do Blackboard: O recurso especificado não foi encontrado ou você não tem permissão para acessá-lo ou Erro de acesso!

Com as seguintes exceções no registro bb-services:

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]
Resolução
  1. Navegue até o Painel do administrador.

  2. Em Integrações, clique em Building Blocks.

  3. Clique em Ferramentas instaladas .

  4. Localize Provedor de autenticação – SAML na lista. Abra o menu e clique em Configurações.

  5. Em Configurações do algoritmo de assinatura, escolha SHA-256 na lista. Depois de selecionar o Tipo de algoritmo de assinatura, reinicie o Building Block SAML para aplicar as novas configurações.

  6. Clique em Enviar para salvar as alterações.

Problema nº 5

Depois de inserir as credenciais de acesso na página de acesso do ADFS, um erro pode ser exibido após ser redirecionado para a GUI do Blackboard: O recurso especificado não foi encontrado ou você não tem permissão para acessá-lo ou Erro de acesso!

Com as seguintes exceções no registro bb-services:

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

Conforme definido na exceção SAML acima, o elemento NameID está ausente do Assunto na mensagem Resposta. O problema costuma ocorrer quando a NameID não configurada como um Tipo de declaração de saída em uma Regra de declarações para a Confiança da parte confiável no IdP do ADFS da instituição ou a Regra de declarações para a NameID não está na ordem adequada para a Confiança da parte confiável no IdP do ADFS da instituição, o que, por sua vez, faz o elemento NameID estar ausente no Assunto na mensagem de Resposta.

Exemplo: o elemento NameID está ausente
<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>
Exemplo: o elemento NameID está presente
<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>

Nota

Você pode usar o complemento rastreador de SAML do Firefox para visualizar o Assunto na mensagem de Resposta.

Resolução

Existem três métodos para resolver esse problema.

  1. Confirme se as etapas do Guia de configuração SAML B2 para ADFS foram adequadamente seguidas e faça as alterações necessárias para transformar uma declaração de chegada para a Confiança da terceira parte confiável para o IdP do ADFS:

    1. Clique em Editar regra de declarações.

    2. Clique em Adicionar regra.

    3. Na página Selecionar modelo de regra, selecione Transformar uma declaração de entrada para o modelo de regra de declaração e, em seguida, selecione Avançar.

    4. Na página Configurar regra, no campo Nome de regra de declaração, digite Transformar e-mail em código de nome.

    5. O tipo de declaração de entrada deve ser SamAccountName (deve corresponder ao Tipo de declaração de saída criado inicialmente na regra Transformar nome de usuário em NameID).

    6. O Tipo de declaração de saída é o código do nome.

    7. O formato de código de nome de saída é E-mail.

    8. Confirme que Passar por todos os valores de declaração está selecionado e selecione Concluir.

    9. Clique em OK para salvar a regra e OK novamente para concluir os mapeamentos de atributo.

  2. Para a ordem de Regras de declarações usadas para o IdP do ADFS, garanta que nenhuma regra opcional ocorra antes da regra com o elemento NameID.

  3. Se estiver usando um atributo personalizado, certifique-se de que o elemento NameID esteja na Confiança de terceira parte confiável pois a Blackboard ainda espera que o IdP do ADFS libere um valor NameID.

Problema nº 6

Quando conectado ao Blackboard por meio da autenticação SAML, o usuário tenta fazer logout clicando no botão Sair no lado esquerdo da página e, em seguida, clica no botão Encerrar sessão de Acesso único, um Erro de acesso! é exibido imediatamente.

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].

Com a seguinte exceção no registro do bb-services:

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

O erro ocorre devido à configuração Tipo de serviço de saída do sistema único na página Configurações de SAML.

Resolução

A configuração precisa ser definida no Blackboard e no servidor ADFS.

Para o ADFS como o IdP, selecione a configuração Post only e exclua o terminal de redirecionamento para a confiança de terceira parte confiável da instância do Blackboard no servidor do ADFS.

  1. No Blackboard, navegue até > de autenticação do administrador > (nome do provedor) > Configurações SAML > tipo de serviço Logout único.

  2. Clique em Publicar e desmarque a caixa de seleção Redirecionar.

  3. No servidor ADFS, acesse a confiança de terceira parte confiável para sua instância do Blackboard.

  4. Clique em Propriedades > Pontos de extremidade. Dois terminais de saída do sistema SAML são relacionados.

  5. Exclua o terminal Redirecionar. Clique em Excluir terminal para excluí-lo, então selecione Aplicar e OK.

Depois de fazer as alterações acima no Blackboard e no servidor ADFS, o botão de saída do sistema Encerrar sessão de Acesso único funcionará para desconectar corretamente o usuário.

Problema nº 7

Depois de inserir as credenciais de acesso na página de acesso do ADFS, um Erro de acesso! é exibida quando redirecionada para o Blackboard.

Com a seguinte exceção SAML no registro bb-services:

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
Resolução

Há uma opção para regenerar o certificado de criptografia SAML navegando até Administrador do Sistema > Building block > serviço de autenticação – SAML > Configurações > Certificado de regeneração. O problema Erro de Sign On! pode ocorrer se o botão Regenerar certificado for selecionado depois que os metadados do SP já tiverem sido carregados na Confiança de terceira parte confiável para o site do Blackboard no servidor ADFS. Para resolver o problema:

  1. Navegue para Administração do sistema > Autenticação > [Nome do provedor SAML] > Configurações de SAML.

  2. Clique em Gerar ao lado de Metadados do provedor de serviços para salvar o novo arquivo de metadados.

  3. Acesse seu servidor ADFS e carregue os novos metadados do SP para a confiança de terceira parte confiável do seu site do Blackboard.

Nota

Se você gerar um novo certificado nas configurações de B2, será necessário alternar o SAML B2 para Inativo e, então, voltar para Ativo para forçar a alteração. Depois, você pode retornar às configurações do provedor e gerar os novos metadados para importar para o IDP. Se você não alternar as configurações, o certificado antigo ainda poderá ser incluído ao gerar novos metadados. O IDP não será atualizado e, na próxima vez que o Blackboard for reiniciado, ele apresentará o novo certificado. A autenticação SAML será interrompida por causa dessa incompatibilidade.

Metadados de federação

Com os Serviços de Federação do Active Directory (ADFS), como os metadados de uma federação do ADFS normalmente localizados em https://[ADFS Server Hostname]/FederationMetadata/2007-06/FederationMetadata.xml incluem um elemento incompatível com o SAML 2.0, os metadados precisam ser editados para excluir o elemento incompatível antes de serem carregados na seção Configurações do provedor de identidade na página Configurações de autenticação SAML na GUI do Blackboard. Se os metadados com o elemento incompatível forem carregados, ocorrerá um erro ao selecionar o link de acesso SAML na página de acesso do Blackboard: Os metadados da entidade [entidade] e da função {} não foram encontrados. Para referência, o código do erro é [error ID].

E o rastreamento de pilha Java correspondente para o código de erro no registro bb-services tem o seguinte:

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]
Resolução

Como o local de metadados padrão para uma federação do ADFS é https://[ADFS server hostname]/FederationMetadata/2007-06/FederationMetadata.xml:

  1. Baixe esse arquivo e abra-o em um editor de texto. Exclua cuidadosamente a seção que começa com <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> ... </X509Data></KeyInfo> and ending </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. Carregue o arquivo XML de metadados atualizado na GUI do Blackboard na página Configurações de autenticação SAML na seção Configurações do provedor de identidade.

  3. Alterne o provedor de autenticação SAML e SAML B2 para Inativo/Disponível, enquanto o provedor de autenticação SAML estiver no status "Ativado".

Importante

Se uma instituição estiver testando a autenticação SAML em um site da Blackboard e tiver vários provedores de autenticação SAML que compartilham o mesmo arquivo XML de metadados do IdP do ADFS subjacente no site da Blackboard, mesmo que os outros provedores de autenticação SAML estejam definidos como Inativos, eles também precisarão ter o arquivo XML de metadados atualizado carregado na GUI do Blackboard na página Configurações de autenticação SAML na seção Configurações do provedor de identidade. O SAML B2, então, deve ser alternado para Inativo/Disponível, enquanto o status do provedor de autenticação SAML estiver “Ativado”, para garantir que o arquivo XML de metadados atualizado seja reconhecido em todo o sistema.

Método incorreto de pesquisa de usuário

Depois de inserir as credenciais de acesso na página de acesso do ADFS, o usuário é redirecionado para a GUI do Blackboard, mas não está conectado ao Blackboard.

O ÚNICO evento relacionado a autenticação SAML no registro bb-services é:

2016-10-18 13:03:28 -0600 - userName is null or empty
Resolução
  1. Acesse o Blackboard como administrador usando a autenticação interna padrão do Blackboard.

  2. Acesse Administração do sistema > "Nome do provedor de autenticação SAML" > Editar.

  3. Altere o Método de pesquisa do usuário de Uid em lote para Nome de usuário.

Botão de saída do sistema Encerrar sessão de SSO extra

O ADFS tenta adicionar um botão adicional de saída Encerrar sessão de Acesso único no menu Encerrar todas as sessões? página que é exibida após a primeira seleção do botão de saída no canto superior direito da GUI do Blackboard.

Isso é feito adicionando um SingleLogoutService extra ao arquivo de Metadados do IdP:

<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/"/>

Como essa é uma configuração opcional do IdP SAML B2 e a assinatura fornecida no Endpoint de Redirecionamento não está correta, ocorrerá um erro ao clicar no botão adicional Encerrar Sessão de SSO na página Encerrar todas as sessões?: Falha na validação de segurança da mensagem SAML recebida. A validação da assinatura simples da solicitação falhou para o emissor do contexto. Para referência, o código do erro é [error ID].

O rastreamento de pilha Java correspondente para a ID de erro no registro bb-services tem:

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]
Resolução
  1. Acesse o servidor ADFS e vá para a Confiança de terceira parte confiável para a instância do Blackboard.

  2. Clique em a guia Propriedades > Pontos de extremidade.

  3. Na guia Pontos de extremidade, haverá dois Pontos de extremidade de saída do sistema SAML.

  4. Exclua o terminal Redirecionar.

  5. Clique em Excluir terminal para excluí-lo, então selecione Aplicar e OK.

Depois de excluir o terminal Redirecionar, o botão Encerrar sessão de SSO funcionará desconectando o usuário adequadamente.

Como visualizar registros de aplicativo com o visualizador de eventos

Ao solucionar problemas de autenticação SAML do ADFS, pode ser necessário que uma instituição também verifique os registros de aplicativo do ADFS em Visualização de eventos no servidor ADFS para obter mais informações. Isso é particularmente necessário quando a resposta de SAML do ADFS Server tem um status de Solicitação negada, conforme visto a seguir:

<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>

Nota

A resposta SAML pode ser visualizada usando o complemento de rastreador SAML do navegador Firefox.

O status Solicitação negada em uma resposta normalmente indica que ocorreu um problema quando o IdP (ADFS) tentou entender a resposta e processar o resultado fornecido pelo SP (Blackboard).

Para visualizar os registros de aplicativo ADFS com o Visualizador de eventos:

  1. Abra o Visualizador de eventos no ADFS Server.

  2. No menu Visualizar, selecione Mostrar registros analíticos e de depuração.

  3. Na árvore do console, navegue para Registros de aplicativo e serviço > Rastreamento do AD FS > Depurar.

Azure Active Directory

O Azure AD é o serviço de gerenciamento de identidade e diretório baseado em nuvem da Microsoft (MS).

Enviar primeira parte do e-mail

Se uma instituição estiver usando o Azure AD como seu IdP e quiser ter apenas a primeira parte do nome de usuário de e-mail do Azure AD usada para o nome de usuário do Blackboard, ela poderá configurar seu IdP do Azure AD para usar a função especial ExtractMailPrefix() para excluir o sufixo de domínio do e-mail ou do nome principal do usuário, resultando na passagem apenas da primeira parte do nome de usuário (por exemplo, "joesmith" em vez de joesmith@example.com).

Se a ID de usuário remoto do Blackboard for urn:oid:1.3.6.1.4.1.5923.1.1.1.6, a configuração Atributo do IdP do Azure terá esta aparência:

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

Portanto, com o exemplo joesmith@example.com nome de usuário de e-mail, ele seria passado assim na declaração SAML do IdP do Azure para o Blackboard:

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

Informações adicionais sobre como usar a função ExtractMailPrefix() estão disponíveis na página de documentação do MS Azure.

IdP do Azure AD atualizando o certificado

Depois de inserir as credenciais de acesso na página de acesso do MS Azure AD, um Erro de acesso! pode ocorrer após o redirecionamento para a IGU do Blackboard.

Com a seguinte exceção no registro do bb-services:

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

Isso é causado pelo IdP do MS Azure AD atualizando o certificado, mas o XML de metadados usado pelo Blackboard SP não está sendo ajustado para refletir o novo certificado.

Resolução
  • O novo arquivo XML de metadados com o novo certificado precisará ser atualizado na página Configurações SAML na GUI do Blackboard para o provedor de autenticação.

  • O SAML B2 e o provedor de autenticação então precisarão ser alternados para Inativo/Disponível, enquanto o status do provedor de autenticação SAML estiver “Ativado”, para que os metadados sejam atualizados com o novo certificado aplicado.

  • Se um site da Blackboard tiver vários provedores de autenticação que compartilham o mesmo certificado subjacente para a mesma ID de entidade IdP subjacente, TODOS esses provedores de autenticação precisarão ser atualizados.

Acesso único iniciado pelo IdP

Se um usuário fizer acesso primeiro no portal do usuário e, em seguida, selecionar o aplicativo para o site do Blackboard, uma nova guia do navegador será aberta para exibir uma mensagem: O recurso especificado não foi encontrado ou você não tem permissão para acessá-lo.

Com os eventos relacionados SAML correspondentes no stdout-stderr.log:

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

A seção Configurações do provedor de serviços da página Configurações de autenticação SAML foi alterada e a opção habilitar acesso único automático deve ser marcada para permitir que um usuário acesse o Blackboard a partir de seu portal. Se estiver habilitada, o URL do ACS também será alterado para incluir um alias.

Erro de documento incorreto

Depois de digitar as credenciais de acesso na página de acesso do provedor de autenticação SAML, um erro Sign On! poderá ocorrer após o redirecionamento para a IGU do Blackboard.

Com a seguinte DOMException e WRONG_DOCUMENT_ERR no registro bb-services:

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]

O motivo pelo qual o problema ocorre é que outro B2/Project alterou o valor da propriedade do sistema javax.xml.parsers.DocumentBuilderFactory de org.apache.xerces.jaxp.DocumentBuilderFactoryImpl para com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl.

Resolução temporária

Até que uma correção seja liberada, as opções de resolução temporárias são:

  1. Reinicie os serviços Bb em cada nó.

  2. Desative a criptografia de resposta SAML no lado do IdP. Uma vez que a comunicação como um todo é por SSL, isso não reduzirá a segurança da autenticação.

Nenhuma opção para adicionar SAML à ordem do provedor

Ao configurar a autenticação SAML, uma instituição pode perceber que não há uma opção para adicionar um provedor de autenticação SAML na seção Ordem do provedor na GUI do Blackboard ao navegar até Administrador do sistema > Building block: Autenticação > Ordem do provedor.

O motivo pelo qual não há uma opção de adicionar um provedor de autenticação SAML à Ordem do provedor é que provedores do tipo de redirecionamento como CAS e SAML entregam a autenticação à origem remota. Esses não estão relacionados na Ordem do provedor porque são considerados a origem autoritativa para autenticação e tratam das próprias falhas de autenticação.

Testar conexão SAML

Há uma opção para testar a conexão de um provedor SAML na seção Autenticação na GUI do Blackboard. O teste de conexão verificará os seguintes itens:

  • Analisar metadados de IdP

  • Conectar-se ao IdP

  • Receber a resposta SAML

  • Analisar a resposta SAML

  • Correspondência de código de usuário remoto

  • Acesse o Blackboard

Para testar a conexão para o provedor de autenticação SAML:

  1. Acesse o Blackboard como administrador.

  2. Navegue até Building Blocks do > de administrador do sistema: autenticação > "Nome do provedor SAML" > Conexão de teste.

  3. Insira as credenciais de acesso do IdP, se solicitado.

O recurso Testar conexão pode ser usado em vez de ativar manualmente o registro de depuração SAML no Blackboard por vários motivos.

O valor de ID da entidade do provedor de identidade exibido na página de saída Conexão de teste é extraído do elemento Emissor no POST SAML do IdP para o Blackboard depois que o usuário é autenticado:

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

Os valores de Atributo SAML exibidos na página de saída Conexão de teste na seção Resposta SAML são extraídos dos elementos Subject e AttributeStatement no POST SAML do IdP para o Blackboard depois que o usuário é autenticado:

<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>

Crie um provedor de autenticação SAML e um IdP para teste

Siga as etapas abaixo para criar um provedor de identidade (IdP) usando a solução de autenticação SSO gratuita da Centrify.

Esse IdP pode ser configurado como o provedor de autenticação SAML em um Blackboard Serviço Provider (SP):

Provedor de serviços da Blackboard
  1. Acesse o sistema na GUI do Blackboard como administrador e navegue até Autenticação de > de administrador do sistema.

  2. Clique em Criar provedor > SAML.

  3. Insira as seguintes configurações:

    • Nome > SAML ou o que você quiser.

    • Provedor de autenticação > Inativo (por enquanto).

    • Método de pesquisa do usuário > Nome do usuário

    • Restringir por nome de host > Usar este provedor para qualquer nome de host

    • Texto do link > Acesso Centrify SAML

  4. Clique em Salvar e configurar.

  5. No campo Código da entidade, defina isso para qualquer valor que quiser (porém, se alterá-lo, você deverá fornecer os metadados do provedor de serviços atualizados para o provedor de identidade). Simplesmente copie/cole o URL do ACS.

  6. Em Metadados do provedor de serviços, selecione Gerar e salve o arquivo na área de trabalho.

  7. Em Fonte de dados, recomendamos criar uma nova origem de dados para esse CENTRIFY nomeado, caso contrário, use SYSTEM ou o que você escolher

  8. Ao lado de Habilitar provisionamento JIT, marque essa caixa para que uma conta seja criada automaticamente ao tentar acessar usando esse provedor de autenticação SAML se o usuário não existir. Se o Provisionamento JIT não estiver selecionado, o usuário no Blackboard precisará ser criado manualmente.

  9. Na lista Fontes de dados compatíveis, selecione as fontes de dados com as quais esse provedor de autenticação deve ser compatível.

  10. Clique em Apontar o provedor de identidade para o Tipo de provedor de identidade.

  11. Ignore os Metadados do provedor de identidade por enquanto; você carregará o arquivo depois que ele tiver sido criado na seção do IdP Centrify.

  12. Para a seção Mapear atributos SAML, use NameID para o Código do usuário remoto.

  13. Clique em Enviar.

Provedor de identidade Centrify
  1. Acesse o site Centrify e selecione Iniciar agora.

  2. Insira suas informações para inscrever-se e selecione Iniciar agora.

  3. Você receberá um e-mail de boas-vindas com suas credenciais de administrador. Use-as para acessar no https://cloud.centrify.com.

  4. Clique em Ignorar na janela Bem-vindo ao Centrify Identify Service.

  5. Na guia Aplicativos na parte superior da página, clique no botão Adicionar aplicativos da web.

  6. Na guia Personalizado, role para baixo e clique no botão Adicionar para SAML. Clique em Sim.

  7. Clique em Fechar na parte inferior da janela Adicionar aplicativos da web.

  8. Vá para a guia Aplicativos. Na seção Configurações do aplicativo, clique no botão Carregar metadados do SP e carregue o arquivo que foi criado na Etapa 6 da seção Blackboard SP.

  9. O URL de serviço do consumidor de asserção deve ser preenchido automaticamente depois do carregamento dos metadados do SP.

  10. Desmarque Criptografar asserção. Isso permite que os atributos que estão sendo liberados do IdP e enviados para o Blackboard sejam visualizados usando o complemento do rastreador SAML do navegador Firefox ou o decodificador de mensagens SAML do Chrome. Uma vez que a comunicação como um todo é por SSL, isso não reduzirá a segurança da autenticação.

  11. Role para baixo e selecione Baixar metadados SAML do provedor de identidade. Salve o arquivo em seu computador.

  12. Clique em Salvar e vá para a próxima seção.

  13. Insira um nome para a seção Descrição. Clique em Salvar e vá para a próxima seção.

  14. Na seção Acesso do usuário, selecione Todos e Administrador do sistema. Clique em Salvar.

  15. Não faça nenhuma seleção na seção Política.

  16. Para a seção Mapeamento de Conta, confirme se userprincipalname está inserido para o nome do campo Serviço de Diretório.

  17. Para a seção Avançado, adicione a seguinte linha à parte inferior do script usado para gerar uma asserção SAML para o aplicativo:

    O script completo será:

    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"));

    Isso permitirá ao IdP Centrify liberar a AttributeStatement com o código do usuário no POST SAML.

    Exemplo:

    <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. Clique em Salvar.

  19. Não será preciso fazer qualquer alteração às seções restantes (Gateway de aplicativo, Changelog e Fluxo de trabalho).

  20. Na guia Aplicativos, confirme que o aplicativo SAML tenha sido implantado de modo automático.

  21. Na guia Usuários, selecione Adicionar usuários, insira as informações da conta e selecione Criar usuário.

  22. Acesse o sistema novamente na GUI do Blackboard como administrador, navegue até Administrador do sistema > Autenticação > Nome do provedor de autenticação SAML > Configurações SAML > Configurações do provedor de identidade, carregue o arquivo de metadados do IdP que foi salvo em sua área de trabalho na Etapa 13 e selecione Enviar.

O usuário do IdP do Centrify recém-criado pode acessar o Blackboard via SAML, selecionando esse provedor de autenticação na página de acesso e sair do Blackboard clicando no botão adicional de saída Encerrar sessão de SSO na página Encerrar todas as sessões? exibida depois que o botão de saída no canto superior direito do Blackboard for clicado.

Altere o texto na página de saída do sistema Encerrar sessão de SSO

Uma instituição pode consultar se é possível alterar o texto na página de saída do sistema da Encerrar sessão de SSO. É possível alterar o texto na página de saída do sistema Encerrar sessão de SSO editando o pacote de idiomas:

  1. Abra o arquivo do pacote de idiomas.

  2. Navegue até auth-provider-saml/src/main/webapp/WEB-INF/bundles/bb-manifest-en_US.properties.

  3. Atualize as chaves de mensagem:

    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

Redirecione os usuários à página de acesso do IdP

A página de acesso padrão do Blackboard apresenta campos de nome de usuário e senha para o provedor de autenticação padrão do Learn. Quando você habilita a autenticação SAML, um pequeno "Entrar usando..." para SAML aparece na parte inferior desta página, portanto, você pode redirecionar os usuários para o servidor de autenticação do IdP automaticamente quando eles acessarem a página de acesso do Blackboard.

Uma opção para fazer isso é navegar até Autenticação de > de administrador do sistema e definir a autenticação interna padrão do Learn como Inativa, o que significa que uma página de acesso não é mais exibida e imediatamente o usuário é redirecionado para o acesso SAML. O problema com essa opção é que ela substitui o URL de acesso padrão e impede qualquer usuário não SAML de acessar.

Para evitar esse problema e atingir quase o mesmo resultado, use uma página de acesso personalizada. Os usuários são redirecionados à página de acesso do IdP do provedor de autenticação SAML do provedor, mas o link de acesso padrão também deve poder ser utilizado.

  1. Verifique se a autenticação do Learn interno está ativa

  2. Na página de acesso padrão, copie o local do redirecionamento do provedor, por exemplo, faça sign-in usando... SAML. Clique com o botão direito do mouse e selecione Copiar local do link.

  3. Navegue até Administrador do sistema > Comunidades > Configurações temáticas e temas > Personalizar página de acesso.

  4. Clique em Baixar ao lado da Página de acesso padrão para baixar o arquivo JSP de acesso padrão.

  5. Abra o arquivo de JSP com um editor de texto. Adicione o HTML de amostra a seguir ao arquivo JSP de acesso e substitua o texto da URL pela URL que foi copiada na Etapa 2.

    <!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. Navegue para Personalizar página de acesso no Learn mais uma vez. Clique em Usar página personalizada e então carregue o arquivo JSP de acesso atualizado.

  7. Depois de fazer as alterações, clique em Visualização em Personalizar página de acesso para confirmar que o redirecionamento está funcionando adequadamente.

Os usuários que forem para o URL principal agora serão redirecionados para a página de acesso para o provedor de autenticação SAML. Os administradores ainda podem acessar o sistema usando a autenticação interna do Learn por meio da página de acesso padrão: /webapps/acesso/?action=default_acesso or/webapps/acesso/acesso.jsp).