2016-08-11 24 views
0
  1. UserServiceImpl:SAML AuthnResponse不被解碼

    @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. 的UserDetails實現:

    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-配置細節

    <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控制器中,Authentication Object的UserDetail沒有填充自定義數據。

  • /登錄控制器:

    @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年8月11日十七時22分16秒DEBUG BaseMessageEncoder:56 - 成功編碼的消息。 2016年8月11日17點22分16秒DEBUG HttpSessionStorage:93 - 存儲消息a399ehchh04afi304hih7e49fd791g2到會話someValue中

    2016年8月11日17點22分16秒INFO SAMLDefaultLogger:127 - AuthNRequest; SUCCESS; someIP; SP-ENTITYID ; IDP-ENTITYID ;;;

    2016-08-11 17:22:37 INFO UserController:18 - 登錄API通過IdP達到。

    2016-08-11 17:22:37 INFO UserController:20 - 用戶詳細信息:org.sprin[email protected]ffffa64e:RemoteIpAddress:Idp-IpAddress; SESSIONID:someValue中

    2016年8月11日17時22分37秒INFO UserController中:21 - 用戶憑證:

    2016年8月11日17時22分37秒INFO UserController中:22 - 主要anonymousUser 2016-08 -11 17:22:37 DEBUG ExceptionHandlerExceptionResolver:133 - 解決處理異常[public org.springframework.http.ResponseEntity com.akamai.marketplace.controller.UserController.login()]:java.lang.ClassCastException:java.lang。字符串不能轉換爲controller.model.SamlUserDTO

    2016-08-11 17:22:37 DEBUG ExceptionHandlerExceptionResolver:361 - 調用@ExceptionHandler方法:public org.springframework.http.ResponseEntity R ESTExceptionHandler.handleExeption(java.lang.Exception) 2016-08-11 17:22:37 ERROR RESTExceptionHandler:60 - 由異常處理程序捕獲的異常: java.lang.ClassCastException:無法將java.lang.String強制轉換爲包。 SamlUserDTO

    回答

    1

    此問題已得到解決。對於面臨類似問題的人在那裏authNResponses不被解碼,即使您擁有覆蓋loadBySAML()方法,請看看這個XML標記在您的安全配置文件:

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

    構造ARG這種過濾器應該是IdP發佈authNResponse的相對URL。即由SP暴露給IdP的終點。 例如在我的情況:

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

    如果沒有明確提及此路徑,默認值將是

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

    所以SAMLProcessorImpl將監聽路徑/ SAML/SSO的SAML消息。

    希望這會有所幫助!