一部のリソースを保護するために OAuth 1.0 を使用する外部パートナーがいます。このリソースにアクセスする必要があり、Spring Boot と Spring Security OAuth を使用してこれを行いたいと考えています。XML 構成を使用したくないので、Java 構成を介してすべてをセットアップする方法を既に検索しました。これを行う方法の例を提供するこのスレッドを見つけました。しかし、OAuth 1.0 フローに関するいくつかのことは、私には明確ではありません。
私のパートナーは、OAuth 用に 4 つのエンドポイントを提供しています。コンシューマー トークンを提供するrequest_token
エンドポイント、エンドポイント、承認エンドポイント、およびaccess_token
エンドポイントです。現在のセットアップ (以下に示す) では、リクエスト トークンを取得でき、承認エンドポイントが呼び出されます。ただし、承認エンドポイントは確認を求めませんが、URL パラメーターとして電子メールとパスワードを期待し、資格情報を確認した後、次を返します。
oauth_verifier=a02ebdc5433242e2b6e582e17b84e313
そして、ここで OAuth フローが行き詰まります。
OAuth 1.0 に関するいくつかの記事を読んだ後、通常の流れは次のとおりです。
- コンシューマ トークン/キーを取得する
request_token
エンドポイント経由でコンシューマー トークンを使用して oauth トークンを取得する- 認証 URL にリダイレクトし、ユーザーに確認を求める
- 検証トークンを使用して消費者にリダイレクトする
access_token
エンドポイント経由でアクセス トークンを取得するためのユーザー検証トークンと oauth トークン
まず、ステップ 3 と 4 がよくわかりません。Spring Security OAuthの例を見つけましたが、アクセスを確認した後、ユーザー/検証者トークンが消費者に送り返される方法が明確ではありませんでした。誰かがこれがどのように行われるか説明してもらえますか?
2 番目: パートナー エンドポイントが確認を求めず、すぐに oauth ベリファイアを返す場合、この設定で Spring Security OAuth を使用するにはどうすればよいですか? パートナーの承認エンドポイントを呼び出し、何らかの方法で検証者を消費者に知らせる独自の承認エンドポイントを実装することを考えていましたが、後半の部分を行う方法がわかりません。
これまでのコードは次のとおりです (上記のスレッドの助けを借りて;ConsumerTokenDto
些細なことなので省略されています)。
応用
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
終点
@RestController
public class Endpoint {
@Autowired
private OAuthRestTemplate oAuthRestTemplate;
private String url = "https://....";
@RequestMapping("/public/v1/meters")
public String getMeters() {
try {
return oAuthRestTemplate.getForObject(URI.create(url), String.class);
} catch (Exception e) {
LOG.error("Exception", e);
return "";
}
}
}
OAuth 構成
@Configuration
@EnableWebSecurity
public class OAuthConfig extends WebSecurityConfigurerAdapter {
@Autowired
private RestTemplateBuilder restTemplateBuilder;
private ConsumerTokenDto consumerTokenDto;
private static final String ID = "meters";
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/**").permitAll();
http.addFilterAfter(this.oauthConsumerContextFilter(), SwitchUserFilter.class);
http.addFilterAfter(this.oauthConsumerProcessingFilter(), OAuthConsumerContextFilterImpl.class);
}
private OAuthConsumerContextFilter oauthConsumerContextFilter() {
OAuthConsumerContextFilter filter = new OAuthConsumerContextFilter();
filter.setConsumerSupport(this.consumerSupport());
return filter;
}
private OAuthConsumerProcessingFilter oauthConsumerProcessingFilter() {
OAuthConsumerProcessingFilter filter = new OAuthConsumerProcessingFilter();
filter.setProtectedResourceDetailsService(this.prds());
LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> map = new LinkedHashMap<>();
// one entry per oauth:url element in xml
map.put(
new AntPathRequestMatcher("/public/v1/**", null),
Collections.singletonList(new SecurityConfig(ID)));
filter.setObjectDefinitionSource(new DefaultFilterInvocationSecurityMetadataSource(map));
return filter;
}
@Bean
OAuthConsumerSupport consumerSupport() {
CoreOAuthConsumerSupport consumerSupport = new CoreOAuthConsumerSupport();
consumerSupport.setProtectedResourceDetailsService(prds());
return consumerSupport;
}
@Bean
ProtectedResourceDetailsService prds() {
InMemoryProtectedResourceDetailsService service = new InMemoryProtectedResourceDetailsService();
Map<String, ProtectedResourceDetails> store = new HashMap<>();
store.put(ID, prd());
service.setResourceDetailsStore(store);
return service;
}
ProtectedResourceDetails prd() {
ConsumerTokenDto consumerToken = getConsumerToken();
BaseProtectedResourceDetails resourceDetails = new BaseProtectedResourceDetails();
resourceDetails.setId(ID);
resourceDetails.setConsumerKey(consumerToken.getKey());
resourceDetails.setSharedSecret(new SharedConsumerSecretImpl(consumerToken.getSecret()));
resourceDetails.setRequestTokenURL("https://.../request_token");
// the authorization URL does not prompt for confirmation but immediately returns an OAuth verifier
resourceDetails.setUserAuthorizationURL(
"https://.../authorize?email=mail&password=pw");
resourceDetails.setAccessTokenURL("https://.../access_token");
resourceDetails.setSignatureMethod(HMAC_SHA1SignatureMethod.SIGNATURE_NAME);
return resourceDetails;
}
// get consumer token from provider
private ConsumerTokenDto getConsumerToken() {
if (consumerTokenDto == null) {
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
body.add("client", "Client");
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(body, headers);
RestTemplate restTemplate = restTemplateBuilder.setConnectTimeout(1000).setReadTimeout(1000).build();
restTemplate.getInterceptors().add(interceptor);
restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()));
ResponseEntity<ConsumerTokenDto> response = restTemplate
.exchange("https://.../consumer_token", HttpMethod.POST, request,
ConsumerTokenDto.class);
consumerTokenDto = response.getBody();
}
return consumerTokenDto;
}
// create oauth rest template
@Bean
public OAuthRestTemplate oAuthRestTemplate() {
OAuthRestTemplate oAuthRestTemplate = new OAuthRestTemplate(prd());
oAuthRestTemplate.getInterceptors().add(interceptor);
return oAuthRestTemplate;
}
}