2014-01-31 94 views
3

我是Spring Security的新用戶,所以請原諒我,如果這是直截了當的。預認證並將用戶名轉發到默認身份驗證提供商

我們正在重寫遺留Web應用程序的UI層。我們決定新的UI層將基於Spring Security和Spring Security來處理安全和授權。

我一直在尋找在新的應用程序中設置安全模擬我們在以前的應用程序中。在舊的應用程序,我們基本上有用戶在兩個入口點:

  • 內部用戶通過其 執行使用客戶端LDAP服務器的實際驗證HTTP基本身份驗證驗證。 這個認證機制是在JBoss服務器上配置的,因此是容器管理的 。
  • 外部用戶通過驗證憑證的第三方驗證服務登錄。外部用戶角色存儲在LDAP服務器中。當第三方身份驗證服務對憑證進行身份驗證時,會使用用戶名和硬編碼密碼在JBoss配置的安全域上對其進行身份驗證,以便加載其角色。

我想我會試着在Spring Security中模仿這個功能,但到目前爲止已經很短​​了。我在測試中使用內存中身份驗證提供程序來代替LDAP,因爲它更容易。我有http內部用戶的基本身份驗證。

我已經嘗試了子類AbstractPreAuthenticatedProcessingFilter並通過此提供憑據,但它確實將憑據正確地轉發給「默認」身份驗證提供程序。

<http> 
    ... 
    <http-basic /> 
    <custom-filter position="PRE_AUTH_FILTER" ref="ExternalLoginFilter" /> 
</http> 

<beans:bean id="ExternalLoginFilter" class="com.foo.ExternalLoginPreAuthenticationFilter"> 
    <beans:property name="authenticationManager" ref="authenticationManager" /> 
</beans:bean> 

<authentication-manager alias="authenticationManager"> 
    <authentication-provider> 
     <user-service> 
      <user name="internal-user" password="password" authorities="ROLE_USER, ROLE_INTERNAL" /> 
      <user name="external-user" password="password" authorities="ROLE_USER, ROLE_EXTERNAL" /> 
     </user-service> 
    </authentication-provider> 
</authentication-manager>` 

這裏是我的ExternalLoginPreAuthenticationFilter:

public class ExternalLoginPreAuthenticationFilter extends AbstractPreAuthenticatedProcessingFilter { 

@Override 
protected Object getPreAuthenticatedCredentials(HttpServletRequest req) { 
    return "password"; 
} 

@Override 
protected Object getPreAuthenticatedPrincipal(HttpServletRequest req) { 
    HttpSession session = req.getSession(false); 
    if(session != null){ 
     return session.getAttribute("app.external-user.username"); 
    } 
    return null; 
} 

}

我還試圖建立一個「preAuthenticatedAuthenticationProvider」像一些例子提出,但似乎期待我的ExternalLoginPreAuthenticationFilter已經解決了用戶角色以及。

任何想法如何配置Spring MVC允許上述情況?基本上,我需要能夠告訴Spring Security使用特定的用戶名/密碼以最少侵入的方式對默認身份驗證提供程序執行登錄,最好不要使用過多的黑客(舊應用程序使用的)。在解決方案

注:雖然拉爾夫的解決方案似乎工作,特別是這部分:

我認爲使用PreAuthenticatedAuthenticationProvider和preAuthenticatedUserDetailsS​​ervice變量設置爲您在內存AuthenticationUserDetailsS​​ervice來做應該是要走的路。

但是,它也似乎與CSRF保護玩得很糟糕。當我登錄並重定向到主頁時,來自此頁面的任何HTTP POST都將通過CSRF檢查。 POST'ing之前的主頁的後續GET修復了問題,所以Spring似乎不恰當地覆蓋了當前CSRF令牌。我發現一個詳細說明問題的bug report。儘管它聲稱是固定的,但我還沒有能夠解決它。雖然錯誤報告鏈接到論壇中的解決方法,但我習慣於遵循似乎可行的解決方法。

的竅門是在AuthenticationManager注入你Controller並做登錄自己:

@Controller 
@RequestMapping(value = "/external-login") 
public class ExternalLoginController { 

    private AuthenticationManager authenticationManager; 

    @Autowired 
    public ExternalLoginController(AuthenticationManager authenticationManager){ 
     this.authenticationManager = authenticationManager; 
    } 

    // ... 

    @RequestMapping(method = RequestMethod.POST) 
    public String login(){ 
     // Do this after third-party authentication service accepts credentials 
     String username = "external-user"; // or whatever username was authenticated by third-party 
     UsernamePasswordAuthenticationToken credentials = new UsernamePasswordAuthenticationToken(username, "password"); 
     Authentication auth = authenticationManager.authenticate(credentials); 
     SecurityContextHolder.getContext().setAuthentication(auth); 

     return "redirect:/"; 
    } 
} 
+0

你有沒有在AbstractPreAuthenticatedProcessingFilter.doAuthenticate中設置斷點來檢查這個方法是否被調用? – Ralph

+0

是的,它被調用。 –

回答

1

的問題是,該AuthenticationProviderAuthenticationManager由提供該認證證書類(通常是一個選擇AbstractAuthenticationToken的子類)。

您的PreAuthenticationProcessingFilter將創建一個PreAuthenticatedAuthenticationToken,通常由PreAuthenticatedAuthenticationProvider「消耗」。

因此,要麼:

  • 您註冊一個AuthenticationProvider是「消費」的PreAuthenticatedAuthenticationProvider令牌,做你想要什麼,或者
  • 更改PreAuthenticationProcessingFilter創建其他類型的令牌(例如UsernamePasswordAuthenticationToken被「消耗」的「正常」的身份驗證提供者使用(的AbstractUserDetailsAuthenticationProvider子類))

我想用PreAuthenticatedAuthenticationProvider並設置preAuthenticatedUserDetailsService變量在內存中AuthenticationUserDetailsService應該是要走的路。

+0

我試過你最後的建議,它似乎工作(使用UserDetailsByNameServiceWrapper作爲UserDetailsS​​ervice)。但是,當我使用這種方法登錄時,CSRF保護似乎打破了。後續的表單帖子給了我一個帶有CSRF失敗錯誤信息的http 403?我試圖將AuthenticationManager注入處理外部登錄的Controller,如果我直接調用該方法並隨後在SecurityContextHolder上設置返回的身份驗證,那麼CSRF和登錄按預期工作。有任何想法嗎? –

相關問題