Spring Securityの複数の認証プロバイダ

1概要

このクイック記事では、Spring Securityで複数のメカニズムを使用してユーザーを認証することに焦点を当てます。

複数の認証プロバイダを設定してそれを行います。

2認証プロバイダ

AuthenticationProvider は、特定のリポジトリからユーザー情報を取得するための抽象概念です。リンク:/データベースによる春のセキュリティ認証[データベース]、リンク:/spring-security-ldap[LDAP]、リンク:/spring-security-authentication-provider[カスタムサードパーティソース]など)取得したユーザー情報を使用して、提供された資格情報を検証します。

簡単に言うと、複数の認証プロバイダが定義されている場合、プロバイダは宣言されている順序で問い合わせられます。

簡単に説明するために、カスタム認証プロバイダとメモリ内認証プロバイダの2つの認証プロバイダを設定します。

3 Mavenの依存関係

まず、必要なSpring Securityの依存関係をWebアプリケーションに追加しましょう。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

そして、Spring Bootなしで:

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>5.0.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-core</artifactId>
    <version>5.0.4.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    <version>5.0.4.RELEASE</version>
</dependency>

これらの依存関係の最新版はhttps://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22org.springframework.security%22%20AND%20a%3A%22spring-securityで見つけることができます。 -web%22[spring-security-web]、https://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22org.springframework.security%22%20AND%20a%3A%22spring -security-core%22[spring-security-core]、およびhttps://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22org.springframework.security%22%20AND%20a% 3A%22スプリングセキュリティ設定%22[spring-security-config]。

4カスタム認証プロバイダ

AuthneticationProvider インターフェースを実装してカスタム認証プロバイダーを作成しましょう _. _

認証を試みる authenticate メソッドを実装します。入力 Authentication オブジェクトには、ユーザーが指定したユーザー名とパスワードの資格情報が含まれています。

認証が成功すると、 authenticate メソッドは完全に入力された Authentication オブジェクトを返します。認証が失敗すると、 AuthenticationException 型の例外がスローされます。

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
    @Override
    public Authentication authenticate(Authentication auth)
      throws AuthenticationException {
        String username = auth.getName();
        String password = auth.getCredentials()
            .toString();

        if ("externaluser".equals(username) && "pass".equals(password)) {
            return new UsernamePasswordAuthenticationToken
              (username, password, Collections.emptyList());
        } else {
            throw new
              BadCredentialsException("External system authentication failed");
        }
    }

    @Override
    public boolean supports(Class<?> auth) {
        return auth.equals(UsernamePasswordAuthenticationToken.class);
    }
}

当然、これはここでの例の目的のための単純な実装です。

** 5複数の認証プロバイダの設定

それでは、 CustomAuthenticationProvider とインメモリ認証プロバイダーをSpring Securityの設定に追加しましょう。

5.1. Javaの設定

設定クラスで、 AuthenticationManagerBuilder を使用して認証プロバイダを作成して追加しましょう。

最初に CustomAuthenticationProvider 、次に inMemoryAuthentication() を使用してインメモリ認証プロバイダを作成します。

また、URLパターン " /api/ "へのアクセスを認証する必要があることを確認しています。

@EnableWebSecurity
public class MultipleAuthProvidersSecurityConfig
  extends WebSecurityConfigurerAdapter {
    @Autowired
    CustomAuthenticationProvider customAuthProvider;

    @Override
    public void configure(AuthenticationManagerBuilder auth)
      throws Exception {

        auth.authenticationProvider(customAuthProvider);
        auth.inMemoryAuthentication()
            .withUser("memuser")
            .password(encoder().encode("pass"))
            .roles("USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.httpBasic()
            .and()
            .authorizeRequests()
            .antMatchers("/api/** ** ")
            .authenticated();
    }


    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

5.2. XML設定

あるいは、Java設定の代わりにXML設定を使いたい場合は、

<security:authentication-manager>
    <security:authentication-provider>
        <security:user-service>
            <security:user name="memuser" password="pass"
              authorities="ROLE__USER"/>
        </security:user-service>
    </security:authentication-provider>
    <security:authentication-provider
      ref="customAuthenticationProvider"/>
</security:authentication-manager>

<security:http>
    <security:http-basic/>
    <security:intercept-url pattern="/api/** ** "
      access="isAuthenticated()"/>
</security:http>

6. アプリケーション

次に、2つの認証プロバイダによって保護されている単純なRESTエンドポイントを作成しましょう。

このエンドポイントにアクセスするには、有効なユーザー名とパスワードを入力する必要があります。

当社の認証プロバイダは資格を検証し、アクセスを許可するかどうかを決定します。

@RestController
public class MultipleAuthController {
    @GetMapping("/api/ping")
    public String getPing() {
        return "OK";
    }
}

7. テスト中

最後に、セキュリティ保護されたアプリケーションへのアクセスをテストしましょう。有効な認証情報が指定されている場合にのみアクセスが許可されます。

@Autowired
private TestRestTemplate restTemplate;

@Test
public void givenMemUsers__whenGetPingWithValidUser__thenOk() {
    ResponseEntity<String> result
      = makeRestCallToGetPing("memuser", "pass");

    assertThat(result.getStatusCodeValue()).isEqualTo(200);
    assertThat(result.getBody()).isEqualTo("OK");
}

@Test
public void givenExternalUsers__whenGetPingWithValidUser__thenOK() {
    ResponseEntity<String> result
      = makeRestCallToGetPing("externaluser", "pass");

    assertThat(result.getStatusCodeValue()).isEqualTo(200);
    assertThat(result.getBody()).isEqualTo("OK");
}

@Test
public void givenAuthProviders__whenGetPingWithNoCred__then401() {
    ResponseEntity<String> result = makeRestCallToGetPing();

    assertThat(result.getStatusCodeValue()).isEqualTo(401);
}

@Test
public void givenAuthProviders__whenGetPingWithBadCred__then401() {
    ResponseEntity<String> result
      = makeRestCallToGetPing("user", "bad__password");

    assertThat(result.getStatusCodeValue()).isEqualTo(401);
}

private ResponseEntity<String>
  makeRestCallToGetPing(String username, String password) {
    return restTemplate.withBasicAuth(username, password)
      .getForEntity("/api/ping", String.class, Collections.emptyMap());
}

private ResponseEntity<String> makeRestCallToGetPing() {
    return restTemplate
      .getForEntity("/api/ping", String.class, Collections.emptyMap());
}

8結論

このクイックチュートリアルでは、Spring Securityで複数の認証プロバイダを設定する方法を説明しました。カスタム認証プロバイダとインメモリ認証プロバイダを使用して簡単なアプリケーションを保護しました。

また、アプリケーションへのアクセスには、少なくとも1つの認証プロバイダが検証できる資格情報が必要であることを確認するためのテストも作成しました。

いつものように、実装の完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/spring-security-mvc-boot[GitHub上で動く]にあります。