1概要

この記事では、Spring MVCのテストサポートで

OAuth

を使用して保護されているAPIをテストする方法を説明します。


2認証およびリソースサーバー

認証およびリソースサーバーの設定方法に関するチュートリアルについては、この前回の記事を参照してください。

私たちの認可サーバーは

JdbcTokenStore

を使用してid

“ fooClientIdPassword”

とpassword

“ secret”

を持つクライアントを定義し、そして

password

grantタイプをサポートします。

リソースサーバーは

/employee

のURLをADMINロールに制限します。

Spring Bootバージョン1.5.0以降、セキュリティアダプタはOAuthリソースアダプタよりも優先されるため、順序を逆にするには、

WebSecurityConfigurerAdapter

クラスに

@ Order(SecurityProperties.ACCESS

OVERRIDE

ORDER)

のアノテーションを付ける必要があります。

それ以外の場合、SpringはSpring OAuthルールではなくSpring Securityルールに基づいて要求されたURLにアクセスしようとします。トークン認証を使用すると403エラーが発生します。


3サンプルAPIの定義

まず、2つのプロパティを持つ

Employee

という単純なPOJOを作成しましょう。これらのプロパティはAPIを通じて操作します。

public class Employee {
    private String email;
    private String name;

   //standard constructor, getters, setters
}

次に、

Employee

オブジェクトを取得してリストに保存するための2つのリクエストマッピングを持つコントローラを定義しましょう。

@Controller
public class EmployeeController {

    private List<Employee> employees = new ArrayList<>();

    @GetMapping("/employee")
    @ResponseBody
    public Optional<Employee> getEmployee(@RequestParam String email) {
        return employees.stream()
          .filter(x -> x.getEmail().equals(email)).findAny();
    }

    @PostMapping("/employee")
    @ResponseStatus(HttpStatus.CREATED)
    public void postMessage(@RequestBody Employee employee) {
        employees.add(employee);
    }
}

  • これを機能させるには、追加のJDK 8 Jacksonモジュール** が必要です。そうでないと、

    Optional

    クラスは正しくシリアライズ/デシリアライズされません。

    jackson-datatype-jdk8

    の最新バージョンはMaven Centralからダウンロードできます。


4 APIのテスト


4.1. テストクラスの設定

APIをテストするために、

AuthorizationServerApplication

クラスを使用してアプリケーション構成を読み取る

@ SpringBootTest

というアノテーションが付けられたテストクラスを作成します。

Spring MVCのテストサポートでセキュアなAPIをテストするには、

WebAppplicationContext

および

Spring Security Filter Chain

Beanをインジェクトする必要があります。テストを実行する前に、これらを使用して

MockMvc

インスタンスを取得します。

@RunWith(SpringRunner.class)
@WebAppConfiguration
@SpringBootTest(classes = AuthorizationServerApplication.class)
public class OAuthMvcTest {

    @Autowired
    private WebApplicationContext wac;

    @Autowired
    private FilterChainProxy springSecurityFilterChain;

    private MockMvc mockMvc;

    @Before
    public void setup() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
          .addFilter(springSecurityFilterChain).build();
    }
}


4.2. アクセストークンの取得

簡単に言うと、

OAuth2


で保護されたAPIは、

Bearer <access

token>

の値を持つ

Authorization__ヘッダー

を受け取ることを期待しています。

必要な

Authorization

ヘッダーを送信するには、まず

/oauth/token

エンドポイントにPOSTリクエストを送信して有効なアクセストークンを取得する必要があります。このエンドポイントには、OAuthクライアントのIDとシークレット、および

client

id



grant

type



username

、および

password

を指定するパラメータのリストを使用したHTTP基本認証が必要です。

Spring MVCのテストサポートを使用して、パラメータを

MultiValueMap

にラップし、

httpBasic

メソッドを使用してクライアント認証を送信できます。

  • トークンを取得するためのPOSTリクエストを送信し、JSONレスポンスから

    access

    token__値を読み取るメソッドを作成しましょう。

private String obtainAccessToken(String username, String password) throws Exception {

    MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
    params.add("grant__type", "password");
    params.add("client__id", "fooClientIdPassword");
    params.add("username", username);
    params.add("password", password);

    ResultActions result
      = mockMvc.perform(post("/oauth/token")
        .params(params)
        .with(httpBasic("fooClientIdPassword","secret"))
        .accept("application/json;charset=UTF-8"))
        .andExpect(status().isOk())
        .andExpect(content().contentType("application/json;charset=UTF-8"));

    String resultString = result.andReturn().getResponse().getContentAsString();

    JacksonJsonParser jsonParser = new JacksonJsonParser();
    return jsonParser.parseMap(resultString).get("access__token").toString();
}


4.3. GETリクエストとPOSTリクエストのテスト

アクセストークンは、

header( “Authorization”、 “Bearer” + accessToken)

メソッドを使用してリクエストに追加できます。


Authorization

ヘッダーを使用せずに、保護されたマッピングの1つにアクセスし、

nauthorized

ステータスコードを受け取ることを確認しましょう。

@Test
public void givenNoToken__whenGetSecureRequest__thenUnauthorized() throws Exception {
    mockMvc.perform(get("/employee")
      .param("email", EMAIL))
      .andExpect(status().isUnauthorized());
}

ADMINの役割を持つユーザーのみが

/employee

のURLにアクセスできるように指定しました。

USER

ロールを持つユーザーのアクセストークンを取得し、

forbidden

​​ステータスコードを受け取ることを確認するテストを作成しましょう。

@Test
public void givenInvalidRole__whenGetSecureRequest__thenForbidden() throws Exception {
    String accessToken = obtainAccessToken("user1", "pass");
    mockMvc.perform(get("/employee")
      .header("Authorization", "Bearer " + accessToken)
      .param("email", "[email protected]"))
      .andExpect(status().isForbidden());
}

次に、有効なアクセストークンを使用して、

Employee

オブジェクトを作成するためのPOSTリクエストを送信し、次に作成されたオブジェクトを読み取るためのGETリクエストを送信して、APIをテストしましょう。

@Test
public void givenToken__whenPostGetSecureRequest__thenOk() throws Exception {
    String accessToken = obtainAccessToken("admin", "nimda");

    String employeeString = "{\"email\":\"[email protected]\",\"name\":\"Jim\"}";

    mockMvc.perform(post("/employee")
      .header("Authorization", "Bearer " + accessToken)
      .contentType(application/json;charset=UTF-8)
      .content(employeeString)
      .accept(application/json;charset=UTF-8))
      .andExpect(status().isCreated());

    mockMvc.perform(get("/employee")
      .param("email", "[email protected]")
      .header("Authorization", "Bearer " + accessToken)
      .accept("application/json;charset=UTF-8"))
      .andExpect(status().isOk())
      .andExpect(content().contentType(application/json;charset=UTF-8))
      .andExpect(jsonPath("$.name", is("Jim")));
}


5結論

このクイックチュートリアルでは、Spring MVCテストサポートを使用してOAuthで保護されたAPIをテストする方法を説明しました。

例の完全なソースコードはhttps://github.com/Baeldung/spring-security-oauth[GitHubプロジェクト]にあります。

テストを実行するために、プロジェクトには実行可能な

mvc

プロファイルがあります。

mvn clean install -Pmvc.

コマンドを使用します。