1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.bremersee.security.authentication;
18
19 import java.io.IOException;
20 import java.util.Optional;
21 import net.minidev.json.JSONObject;
22 import net.minidev.json.JSONValue;
23 import org.bremersee.exception.AccessTokenRetrieverAuthenticationException;
24 import org.springframework.http.HttpEntity;
25 import org.springframework.http.HttpHeaders;
26 import org.springframework.http.HttpMethod;
27 import org.springframework.http.HttpStatus;
28 import org.springframework.http.MediaType;
29 import org.springframework.http.client.ClientHttpResponse;
30 import org.springframework.lang.NonNull;
31 import org.springframework.util.StringUtils;
32 import org.springframework.web.client.DefaultResponseErrorHandler;
33 import org.springframework.web.client.RestTemplate;
34
35
36
37
38
39
40 public class RestTemplateAccessTokenRetriever implements AccessTokenRetriever<String> {
41
42 private final RestTemplate restTemplate;
43
44 private final AccessTokenCache accessTokenCache;
45
46
47
48
49
50
51 public RestTemplateAccessTokenRetriever(RestTemplate restTemplate) {
52 this(restTemplate, null);
53 }
54
55
56
57
58
59
60
61 public RestTemplateAccessTokenRetriever(
62 RestTemplate restTemplate,
63 AccessTokenCache accessTokenCache) {
64
65 this.restTemplate = restTemplate;
66 this.restTemplate.setErrorHandler(new ErrorHandler());
67 this.accessTokenCache = accessTokenCache;
68 }
69
70 @Override
71 public String retrieveAccessToken(AccessTokenRetrieverProperties input) {
72 final String cacheKey = input.createCacheKeyHashed();
73 return Optional.ofNullable(accessTokenCache)
74 .flatMap(cache -> cache.findAccessToken(cacheKey))
75 .orElseGet(() -> {
76 final HttpHeaders headers = new HttpHeaders();
77 headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
78 input.getBasicAuthProperties()
79 .ifPresent(basicAuthProperties -> headers.setBasicAuth(
80 basicAuthProperties.getUsername(),
81 basicAuthProperties.getPassword()));
82 final HttpEntity<?> request = new HttpEntity<>(input.createBody(), headers);
83 final String response = restTemplate.exchange(
84 input.getTokenEndpoint(),
85 HttpMethod.POST,
86 request,
87 String.class)
88 .getBody();
89 final JSONObject json = (JSONObject) JSONValue.parse(response);
90 final String accessToken = json.getAsString("access_token");
91 if (StringUtils.hasText(accessToken)) {
92 if (accessTokenCache != null) {
93 accessTokenCache.putAccessToken(cacheKey, accessToken);
94 }
95 return accessToken;
96 }
97 throw new AccessTokenRetrieverAuthenticationException(HttpStatus.UNAUTHORIZED,
98 "There is no access token in the response: " + accessToken);
99 });
100 }
101
102 private static class ErrorHandler extends DefaultResponseErrorHandler {
103
104 @Override
105 protected void handleError(final ClientHttpResponse response, @NonNull final HttpStatus statusCode)
106 throws IOException {
107 final String statusText = response.getStatusText();
108 throw new AccessTokenRetrieverAuthenticationException(statusCode, statusText);
109 }
110 }
111
112 }