Skip to content
Snippets Groups Projects
Commit fa4bf6f1 authored by Sonia Zorba's avatar Sonia Zorba
Browse files

Added refresh token support

parent 98edfafe
Branches
No related tags found
No related merge requests found
...@@ -61,7 +61,7 @@ export default { ...@@ -61,7 +61,7 @@ export default {
} }
#loading { #loading {
position: absolute; position: fixed;
top: 0; top: 0;
bottom: 0; bottom: 0;
right: 0; right: 0;
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId> <artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version> <version>2.1.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository --> <relativePath/> <!-- lookup parent from repository -->
</parent> </parent>
<groupId>it.inaf.ia2</groupId> <groupId>it.inaf.ia2</groupId>
...@@ -23,15 +23,15 @@ ...@@ -23,15 +23,15 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.security.oauth.boot</groupId> <groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId> <artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId> <artifactId>spring-boot-starter-jdbc</artifactId>
...@@ -52,11 +52,6 @@ ...@@ -52,11 +52,6 @@
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Embedded PostgreSQL: --> <!-- Embedded PostgreSQL: -->
<dependency> <dependency>
<groupId>com.opentable.components</groupId> <groupId>com.opentable.components</groupId>
......
...@@ -5,17 +5,16 @@ import java.util.Map; ...@@ -5,17 +5,16 @@ import java.util.Map;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
public class CustomAuthenticationData extends UsernamePasswordAuthenticationToken { public class CustomAuthenticationData extends UsernamePasswordAuthenticationToken {
private final Map<String, Object> attributes; private final Map<String, Object> attributes;
private final OAuth2AccessToken accessToken; private final OAuth2AccessToken accessToken;
private final OAuth2RefreshToken refreshToken; private final String refreshToken;
public CustomAuthenticationData(String username, Map<String, Object> attributes, public CustomAuthenticationData(String username, Map<String, Object> attributes,
Collection<? extends GrantedAuthority> authorities, Collection<? extends GrantedAuthority> authorities,
OAuth2AccessToken accessToken, OAuth2RefreshToken refreshToken) { OAuth2AccessToken accessToken, String refreshToken) {
super(username, "N/A", authorities); super(username, "N/A", authorities);
this.attributes = attributes; this.attributes = attributes;
this.accessToken = accessToken; this.accessToken = accessToken;
...@@ -30,7 +29,7 @@ public class CustomAuthenticationData extends UsernamePasswordAuthenticationToke ...@@ -30,7 +29,7 @@ public class CustomAuthenticationData extends UsernamePasswordAuthenticationToke
return accessToken; return accessToken;
} }
public OAuth2RefreshToken getRefreshToken() { public String getRefreshToken() {
return refreshToken; return refreshToken;
} }
} }
...@@ -6,7 +6,6 @@ import org.springframework.security.core.Authentication; ...@@ -6,7 +6,6 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
import org.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter; import org.springframework.security.oauth2.provider.token.DefaultUserAuthenticationConverter;
import org.springframework.security.oauth2.provider.token.store.jwk.JwkTokenStore; import org.springframework.security.oauth2.provider.token.store.jwk.JwkTokenStore;
...@@ -25,8 +24,9 @@ public class CustomIdTokenConverter extends DefaultUserAuthenticationConverter { ...@@ -25,8 +24,9 @@ public class CustomIdTokenConverter extends DefaultUserAuthenticationConverter {
OAuth2AccessToken token = jwkTokenStore.readAccessToken(idToken); OAuth2AccessToken token = jwkTokenStore.readAccessToken(idToken);
String refreshToken = (String) map.get("refresh_token");
Map<String, Object> claims = token.getAdditionalInformation(); Map<String, Object> claims = token.getAdditionalInformation();
OAuth2RefreshToken refreshToken = token.getRefreshToken();
String principal = (String) claims.get("sub"); String principal = (String) claims.get("sub");
......
...@@ -16,12 +16,14 @@ public class SessionData { ...@@ -16,12 +16,14 @@ public class SessionData {
private String userId; private String userId;
private String accessToken; private String accessToken;
private String refreshToken;
@PostConstruct @PostConstruct
public void init() { public void init() {
CustomAuthenticationData authn = (CustomAuthenticationData) ((OAuth2Authentication) request.getUserPrincipal()).getUserAuthentication(); CustomAuthenticationData authn = (CustomAuthenticationData) ((OAuth2Authentication) request.getUserPrincipal()).getUserAuthentication();
userId = (String) authn.getPrincipal(); userId = (String) authn.getPrincipal();
accessToken = (String) authn.getAccessToken().getValue(); accessToken = (String) authn.getAccessToken().getValue();
refreshToken = authn.getRefreshToken();
} }
public String getUserId() { public String getUserId() {
...@@ -31,4 +33,16 @@ public class SessionData { ...@@ -31,4 +33,16 @@ public class SessionData {
public String getAccessToken() { public String getAccessToken() {
return accessToken; return accessToken;
} }
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public String getRefreshToken() {
return refreshToken;
}
public void setRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
}
} }
...@@ -5,7 +5,9 @@ import it.inaf.ia2.gms.model.RapUser; ...@@ -5,7 +5,9 @@ import it.inaf.ia2.gms.model.RapUser;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Function;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.ParameterizedTypeReference;
...@@ -13,7 +15,11 @@ import org.springframework.http.HttpEntity; ...@@ -13,7 +15,11 @@ import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
@Component @Component
...@@ -22,11 +28,30 @@ public class RapClient { ...@@ -22,11 +28,30 @@ public class RapClient {
@Value("${rap.ws-url}") @Value("${rap.ws-url}")
private String rapBaseUrl; private String rapBaseUrl;
@Autowired @Value("${security.oauth2.client.access-token-uri}")
private SessionData sessionData; private String accessTokenUri;
@Value("${security.oauth2.client.client-id}")
private String clientId;
@Value("${security.oauth2.client.client-secret}")
private String clientSecret;
@Value("${security.oauth2.client.scope}")
private String scope;
private final SessionData sessionData;
private final RestTemplate rapRestTemplate;
private final RestTemplate refreshTokenRestTemplate;
@Autowired @Autowired
private RestTemplate rapRestTemplate; public RapClient(SessionData sessionData, RestTemplate rapRestTemplate) {
this.sessionData = sessionData;
this.rapRestTemplate = rapRestTemplate;
this.refreshTokenRestTemplate = new RestTemplate();
}
public List<RapUser> getUsers(Set<String> identifiers) { public List<RapUser> getUsers(Set<String> identifiers) {
...@@ -35,8 +60,11 @@ public class RapClient { ...@@ -35,8 +60,11 @@ public class RapClient {
} }
String url = rapBaseUrl + "/user?identifiers=" + String.join(",", identifiers); String url = rapBaseUrl + "/user?identifiers=" + String.join(",", identifiers);
return rapRestTemplate.exchange(url, HttpMethod.GET, getEntity(), new ParameterizedTypeReference<List<RapUser>>() {
return httpCall(entity -> {
return rapRestTemplate.exchange(url, HttpMethod.GET, entity, new ParameterizedTypeReference<List<RapUser>>() {
}).getBody(); }).getBody();
});
} }
public List<RapUser> searchUsers(String searchText) { public List<RapUser> searchUsers(String searchText) {
...@@ -46,12 +74,24 @@ public class RapClient { ...@@ -46,12 +74,24 @@ public class RapClient {
} }
String url = rapBaseUrl + "/user?search=" + searchText; String url = rapBaseUrl + "/user?search=" + searchText;
return rapRestTemplate.exchange(url, HttpMethod.GET, getEntity(), new ParameterizedTypeReference<List<RapUser>>() {
return httpCall(entity -> {
return rapRestTemplate.exchange(url, HttpMethod.GET, entity, new ParameterizedTypeReference<List<RapUser>>() {
}).getBody(); }).getBody();
});
}
private <R> R httpCall(Function<HttpEntity<?>, R> function) {
return httpCall(function, null);
} }
private HttpEntity<?> getEntity() { private <R, T> R httpCall(Function<HttpEntity<?>, R> function, T body) {
return getEntity(null); try {
return function.apply(getEntity(body));
} catch (HttpClientErrorException.Unauthorized ex) {
refreshToken();
return function.apply(getEntity(body));
}
} }
private <T> HttpEntity<T> getEntity(T body) { private <T> HttpEntity<T> getEntity(T body) {
...@@ -63,4 +103,27 @@ public class RapClient { ...@@ -63,4 +103,27 @@ public class RapClient {
return new HttpEntity<>(body, headers); return new HttpEntity<>(body, headers);
} }
private void refreshToken() {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.setBasicAuth(clientId, clientSecret);
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.add("grant_type", "refresh_token");
map.add("refresh_token", sessionData.getRefreshToken());
map.add("scope", scope.replace(",", " "));
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
ResponseEntity<Map> response = refreshTokenRestTemplate.postForEntity(accessTokenUri, request, Map.class);
Map<String, String> values = response.getBody();
sessionData.setAccessToken(values.get("access_token"));
sessionData.setRefreshToken(values.get("refresh_token"));
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment