Spring MVCによるOAuthで保護されたAPIのテスト
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.
コマンドを使用します。