SAML AuthnResponse не декодируется после успешной аутентификации

  1. UserServiceImpl:

    @Override
    public Object loadUserBySAML(SAMLCredential credential)  throws UsernameNotFoundException{
    String userID = credential.getNameID().getValue();
    
    logger.info(userID + " is logged in");
    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
    authorities.add(authority);
    
    List<Attribute> userAttributes = credential.getAttributes();
    logger.info("Credential attributes: " + userAttributes);
    for (int attrIndex = 0; attrIndex < userAttributes.size(); attrIndex++) {
        Attribute attr = userAttributes.get(attrIndex);
        List<XMLObject> attrValues = attr.getAttributeValues();
        StringBuilder strBuilder = new StringBuilder();
        for (int attrValueIndex = 0; attrValueIndex < attrValues.size(); attrValueIndex++) {
            XMLObject currObj = attrValues.get(attrValueIndex);
            strBuilder.append(currObj.toString()).append(",");
        }
        strBuilder.deleteCharAt(strBuilder.length() - 1);
        logger.info(attr.getFriendlyName() + ", " + strBuilder.toString());
        String samlAttrValue = strBuilder.toString();
        switch (attr.getFriendlyName()) {
        case "userName":
            samlUserAttribute.setUserName(samlAttrValue);
        case "email":
            samlUserAttribute.setEmail(samlAttrValue);
            break;
        case "firstName":
            samlUserAttribute.setFirstName(samlAttrValue);
            break;
        case "lastName":
            samlUserAttribute.setLastName(samlAttrValue);
            break;
        case "userType":
            samlUserAttribute.setUserType(samlAttrValue);
            break;
        case "accountName":
            samlUserAttribute.setAccountName(samlAttrValue);
            break;
        case "contactId":
            samlUserAttribute.setContactId(samlAttrValue);
            break;
        default:
            logger.info("invalid attribute name" + attr.getFriendlyName());
        }
    }
    logger.info("User details obtained: " + samlUserAttribute);
    return new SamlUserDTO(userID, "<abc123>", authorities, samlUserAttribute);
    }
    
  2. Реализация пользовательских сведений:

    private SamlUserAttribute currentUserAttribute;
    private String password;
    private final String username;
    private final Set<GrantedAuthority> authorities;
    private final boolean accountNonExpired;
    private final boolean accountNonLocked;
    private final boolean credentialsNonExpired;
    private final boolean enabled;
    .. setter/getter/contructors for userDetails...
    

    3. Детали конфигурации безопасности

    <security:http entry-point-ref="samlEntryPoint" access-decision-manager-ref="accessDecisionManager" authentication-manager-ref="authenticationManager"
    use-expressions="true">
      <security:intercept-url pattern="/login" access="permitAll"/>
      <security:intercept-url pattern="/**"
        access="isFullyAuthenticated()" />
      <security:custom-filter after="BASIC_AUTH_FILTER"
        ref="samlFilter" />
      <security:csrf disabled="true"/>
    </security:http>
    
    <bean id="samlFilter" class="org.springframework.security.web.FilterChainProxy">
      <security:filter-chain-map request-matcher="ant">
         <security:filter-chain pattern="/**"
            filters="samlEntryPoint" />
         </security:filter-chain-map>
     </bean>
    
    <bean id="samlAuthenticationProvider"
    class="org.springframework.security.saml.SAMLAuthenticationProvider">
     <property name="userDetails" ref="UserServiceImpl" />
     <property name="forcePrincipalAsString" value="false" />
    </bean>
    
    <bean id="UserServiceImpl"
    class="com.akamai.marketplace.service.impl.common.UserServiceImpl">
    </bean>
    

При переходе по требуемому URL-адресу я вижу в браузере, что происходит перенаправление IDP, IDP отвечает требуемыми утверждениями, а целевой URL-адрес — /login. Но в моем контроллере /login UserDetail объекта аутентификации не был заполнен пользовательскими данными.

  1. /логин контроллера:

    @RequestMapping(path="/login",method = RequestMethod.POST)
    public ResponseEntity<SamlUserDTO> login() {
     logger.info("login API reached through IdP.");
     Authentication userAuthentication =   SecurityContextHolder.getContext().getAuthentication();
     logger.info("user details: "+userAuthentication.getDetails());
     logger.info("user credentials: "+userAuthentication.getCredentials());
     logger.info("principal " + userAuthentication.getPrincipal());
     SamlUserDTO samlUserDTO1 = (SamlUserDTO) userAuthentication.getPrincipal();
     return ResponseEntity.ok(samlUserDTO1);
    }
    

журналы:

2016-08-11 17:22:16 DEBUG BaseMessageEncoder: 56 — успешно закодированное сообщение. 2016-08-11 17:22:16 DEBUG HttpSessionStorage:93 — Сохранение сообщения a399ehchh04afi304hih7e49fd791g2 в сеансе someValue

2016-08-11 17:22:16 ИНФОРМАЦИЯ SAMLDefaultLogger:127 - AuthNRequest;УСПЕХ;someIP;SP-entityId;Idp-entityId;;;

11.08.2016, 17:22:37 INFO UserController:18 — API входа через IdP.

2016-08-11 17:22:37 INFO UserController:20 — сведения о пользователе: org.springframework.security.web.authentication.WebAuthenticationDetails@ffffa64e: RemoteIpAddress: Idp-IpAddress; Идентификатор сеанса: какое-то значение

2016-08-11 17:22:37 INFO UserController:21 - учетные данные пользователя:

2016-08-11 17:22:37 ИНФОРМАЦИЯ UserController:22 — основной анонимный пользователь 2016-08-11 17:22:37 DEBUG ExceptionHandlerExceptionResolver:133 — Разрешение исключения из обработчика .controller.UserController.login()]: java.lang.ClassCastException: java.lang.String нельзя преобразовать в controller.model.SamlUserDTO

2016-08-11 17:22:37 DEBUG ExceptionHandlerExceptionResolver:361 - Вызов метода @ExceptionHandler: public org.springframework.http.ResponseEntity RESTExceptionHandler.handleExeption(java.lang.Exception) 2016-08-11 17:22:37 ОШИБКА RESTExceptionHandler :60 — Исключение, перехваченное обработчиком исключений: java.lang.ClassCastException: java.lang.String нельзя преобразовать в package.SamlUserDTO


person Meghana    schedule 11.08.2016    source источник


Ответы (1)


этот вопрос решился. Для людей, столкнувшихся с аналогичной проблемой, когда authNResponses не декодируется, даже если вы переопределили метод loadBySAML(), посмотрите на этот тег xml в файле конфигурации безопасности:

<bean id="samlWebSSOProcessingFilter" class="org.springframework.security.saml.SAMLProcessingFilter">

Аргумент конструктора для этого фильтра должен быть относительным URL-адресом, по которому authNResponse будет отправлен IdP. т. е. конечная точка, предоставляемая SP для IdP. пример в моем случае:

<constructor-arg>
        <value type="java.lang.String">/login</value>
</constructor-arg>

Если этот путь не указан явно, значением по умолчанию будет

 public static final String FILTER_URL = "/saml/SSO";

Таким образом, SAMLProcessorImpl будет прослушивать сообщения SAML по пути /saml/SSO.

Надеюсь это поможет!

person Meghana    schedule 12.08.2016