2015-01-13 15 views
5

私のアプリケーションは、次のgithubのプロジェクトで提供されるこの1と同一のトークンサービスを提供していのOAuth2。春に関するセキュリティのOauth 2複数のユーザ認証サービス

私はUserDetailsS​​erviceの私のカスタム実装を提供:

<bean id="userService" class="org.example.core.service.DBUserServiceImpl" /> 

と、次のユーザ認証マネージャ:

<sec:authentication-manager alias="userAuthenticationManager"> 
    <sec:authentication-provider user-service-ref="userService"> 
     <sec:password-encoder ref="passwordEncoder" /> 
    </sec:authentication-provider> 
</sec:authentication-manager> 

今、私は、ユーザー認証(他のUserDetailsS​​ervice)の他の方法を提供したいと思います例:

<bean id="otherUserService" class="org.example.core.service.LDAPUserServiceImpl" /> 

残念ながら私はドキュメントでそれを行う方法を見つけてください。あなたがにDelegatingAuthenticationEntryPointを使用する必要が

  • クエリパラメータ
  • HTTPヘッダ(例えばrealmNameに)

答えて

5

:要求レベルに私はどの方法(利用者サービス)のいずれかで使用するために区別したいと思います複数のエントリポイントを設定します。つまり、複数の認証方法を持つことができます。された次のサンプルコード:

DBUSERエントリポイント:

public class DBUserAuthencticationEntryPoint extends BasicAuthenticationEntryPoint { 

    @Override 
    public void commence(HttpServletRequest request, 
      HttpServletResponse response, AuthenticationException authException) 
      throws IOException, ServletException { 
     super.commence(request, response, authException); 
    } 
} 

LDAPエントリポイント:

public class LDAPAuthencticationEntryPoint extends BasicAuthenticationEntryPoint { 

    @Override 
    public void commence(HttpServletRequest request, 
      HttpServletResponse response, AuthenticationException authException) 
      throws IOException, ServletException { 
     super.commence(request, response, authException); 
    } 
} 

次にあなたが(正しいエントリポイントを選択するRequestMatcher Sを作成する必要がありますヘッダー/領域名に基づいて):

DBUSER要求マッチャ:

RequestMatcher dbUserMatcher = new RequestMatcher() {  
    @Override 
    public boolean matches(HttpServletRequest request) { 
     // Logic to identify a DBUser kind of reqeust 
    } 
}; 

LDAPユーザーrequsetマッチャ:

RequestMatcher ldapMatcher = new RequestMatcher() {  
    @Override 
    public boolean matches(HttpServletRequest request) { 
     // Logic to identify a LDAP kind of reqeust 
    } 
}; 

今、私たちは、DelegatingAuthenticationEntryPointにこれらのmatcherとエントリポイントを追加する必要があります。実行時にDelegatingAuthenticationEntryPointはエントリポイントを取得し、trueを返す正規表現に基づいて認証を行います。プロバイダ管理設定

@Configuration 
@EnableWebSecurity 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 
    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http. 
      authorizeRequests(). 
       regexMatchers("/login.*").permitAll(). 
       regexMatchers("/api.*").fullyAuthenticated().   
     and(). 
      formLogin().loginPage("/login"). 
     and(). 
      exceptionHandling().authenticationEntryPoint(delegatingAuthenticationEntryPoint); 
    } 
} 

DBUserAuthencticationEntryPoint dbUserEntryPoint = new DBUserAuthencticationEntryPoint(); 
LDAPAuthencticationEntryPoint ldapEntryPoint = new LDAPAuthencticationEntryPoint(); 

LinkedHashMap<RequestMatcher,AuthenticationEntryPoint> entryPoints = new LinkedHashMap<RequestMatcher,AuthenticationEntryPoint>(); 
entryPoints.put(ldapMatcher, ldapEntryPoint); 
entryPoints.put(dbUserMatcher, dbUserEntryPoint); 

DelegatingAuthenticationEntryPoint delegatingAuthenticationEntryPoint = new DelegatingAuthenticationEntryPoint(entryPoints); 

configure()方法でHttpSecurityDelegatingAuthenticationEntryPointをマップ

@Bean 
public AuthenticationManager authenticationManager() { 
    return new ProviderManager(Arrays.asList(provider1, provider2); 
} 
+0

OKをインスタンス化するためにどの認証クラスを区別するためにTokenRequestオブジェクトを使用することができます

<oauth:authorization-server client-details-service-ref="client-details-service" token-services-ref="tokenServices"> <oauth:refresh-token/> <oauth:custom-grant token-granter-ref="customPasswordTokenGranter"/> </oauth:authorization-server> 

:私の場合、私はそれを「パスワード」助成金をサポートしていることを意味しているResourceOwnerPasswordTokenGranterを拡張しましたカスタム認証ページ(HTTP RealmNameヘッダーなど)にリダイレクトできるかどうかを確認します。 残念ながら認証ページは提供しませんが、OAuth APIのみを提供します。リクエストが来たときに、RealmNameヘッダーに基づいて適切な認証プロバイダを選択し、Authorization httpヘッダーの資格情報を使用して認証する必要があります。 – Konrad

+0

いいえ、これはあらゆる種類の認証プロセスで動作します。デモのためにフォームベースのログインをしました。フォームベースのログインコードを削除し、 'http.authenticationProvider(authenticationProvider)'を呼び出すことで認証プロバイダを設定してください – Mithun

+0

しかし、標準のOauthフローを使用して、org.springframework.security.authentication.ProviderManagerをユーザ固有の認証マネージャ。私は認証エントリーポイントからそれを行うことができません。 – Konrad

2

を私はMithunが提供するソリューションとは異なる解決策を見つけました。

アプリケーションコンテキストが異なる認証プロバイダを開始したユーザーの認証マネージャが含まれています

customerAuthProviderとadminAuthProviderが異なるuserDetailsサービスとDaoAuthenticationProviderの拡張である
<sec:authentication-manager alias="userAuthenticationManager"> 
    <sec:authentication-provider ref="customerAuthProvider" /> 
    <sec:authentication-provider ref="adminAuthProvider" /> 
</sec:authentication-manager> 

<bean id="customerAuthProvider" class="org.example.security.authentication.provider.CustomerAuthenticationProvider"> 
    <property name="userDetailsService" ref="userService" /> 
    <property name="passwordEncoder" ref="passwordEncoder" /> 
</bean> 

<bean id="adminAuthProvider" class="org.example.security.authentication.provider.AdminAuthenticationProvider"> 
    <property name="userDetailsService" ref="otherUserService" /> 
</bean> 

すべてを行う必要がにあります現在の認証プロバイダが特定の認証を処理できるかどうかを示す「サポート」メソッドをオーバーライドします。

public class CustomerAuthenticationProvider extends DaoAuthenticationProvider { 

    @Override 
    public boolean supports (Class<?> authentication) { 
     return CustomerUsernamePasswordAuthenticationToken.isAssignableFrom(authentication); 
    } 
} 

public class AdminAuthenticationProvider extends DaoAuthenticationProvider { 

    @Override 
    public boolean supports (Class<?> authentication) { 
     return AdminUsernamePasswordAuthenticationToken.isAssignableFrom(authentication); 
    } 
} 

最後に、トークングラントを拡張する必要があります。 、これはあなたが(AdminUsernamePasswordAuthenticationTokenまたはCustomerUsernamePasswordAuthenticationToken)

public class CustomResourceOwnerPasswordTokenGranter extends ResourceOwnerPasswordTokenGranter { 

    protected OAuth2Authentication getOAuth2Authentication (ClientDetails client, TokenRequest tokenRequest) { 
     Map parameters = tokenRequest.getRequestParameters(); 
     String username = (String) parameters.get("username"); 
     String password = (String) parameters.get("password"); 

     String realmName = (String) parameters.get("realm_name"); 

     Authentication userAuth = createAuthentication(username, password, realmName); 
     try { 
      userAuth = this.authenticationManager.authenticate(userAuth); 
     } catch (AccountStatusException ase) { 
      throw new InvalidGrantException(ase.getMessage()); 
     } catch (BadCredentialsException e) { 
      throw new InvalidGrantException(e.getMessage()); 
     } 
     if ((userAuth == null) || (! (userAuth.isAuthenticated()))) { 
      throw new InvalidGrantException("Could not authenticate user: " + username); 
     } 

     OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest); 
     return new OAuth2Authentication(storedOAuth2Request, userAuth); 
    } 

    private Authentication createAuthentication (String username, String password, String realmName) throws InvalidGrantException { 
     // TODO: decide basing on realm name 
    } 
} 
関連する問題