Skip to content

Commit

Permalink
[FIXES #2408] Refresh Token and Logout OIDC requests (#354)
Browse files Browse the repository at this point in the history
  • Loading branch information
afabiani authored May 15, 2024
1 parent 69d0cab commit 16bbce6
Show file tree
Hide file tree
Showing 16 changed files with 381 additions and 212 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public interface SessionServiceDelegate {
/**
* Do the logout.
*
* @param accessToken the current session token.
* @param sessionId the current session token.
*/
void doLogout(String accessToken);
void doLogout(String sessionId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ public SessionToken refresh(String refreshToken, String accessToken) {
}

@Override
public void doLogout(String accessToken) {
userSessionService.removeSession(accessToken);
public void doLogout(String sessionId) {
userSessionService.removeSession(sessionId);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public void setEnabled(boolean enabled) {
}

/**
* @return true if the logged in user should be created on the db if not present. False
* @return true if the logged-in user should be created on the db if not present. False
* otherwise.
*/
public boolean isAutoCreateUser() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,21 +89,24 @@ protected void revokeAuthIfRefreshExpired(Authentication authentication) {
ExpiringOAuth2RefreshToken expiring = (ExpiringOAuth2RefreshToken) refreshToken;
OAuth2Configuration configuration =
(OAuth2Configuration) context.getBean(tokenDetails.getProvider());
if (expiring.getExpiration().after(new Date())) {
OAuth2Configuration.Endpoint revokeEndpoint =
configuration.buildRevokeEndpoint(expiring.getValue());
if (revokeEndpoint != null) {
RestTemplate template = new RestTemplate();
ResponseEntity<String> responseEntity =
template.exchange(
revokeEndpoint.getUrl(),
revokeEndpoint.getMethod(),
null,
String.class);
if (responseEntity.getStatusCode().value() != 200) {
LOGGER.error(
"Error while revoking authorization. Error is: "
+ responseEntity.getBody());
if (configuration != null && configuration.isEnabled()) {
if (expiring.getExpiration().after(new Date())) {
OAuth2Configuration.Endpoint revokeEndpoint =
configuration.buildRevokeEndpoint(
expiring.getValue(), accessToken.getValue(), configuration);
if (revokeEndpoint != null) {
RestTemplate template = new RestTemplate();
ResponseEntity<String> responseEntity =
template.exchange(
revokeEndpoint.getUrl(),
revokeEndpoint.getMethod(),
null,
String.class);
if (responseEntity.getStatusCode().value() != 200) {
LOGGER.error(
"Error while revoking authorization. Error is: {}",
responseEntity.getBody());
}
}
}
}
Expand All @@ -123,7 +126,7 @@ public Authentication get(String accessToken) {

/**
* Put an Authentication instance identified by an accessToken value. If the passed
* Authentication instance those not have a refresh token and we have an old one that has, the
* Authentication instance does not have a refresh token, and we have an old one that has, the
* refresh Token is set to the new instance.
*
* @param accessToken the access token identifying the instance to update
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ private SessionToken sessionToken(String accessToken, String refreshToken, Date
}

@Override
public void doLogout(String accessToken) {
public void doLogout(String sessionId) {
HttpServletRequest request = OAuth2Utils.getRequest();
HttpServletResponse response = OAuth2Utils.getResponse();
KeyCloakHelper helper = GeoStoreContext.bean(KeyCloakHelper.class);
Expand Down Expand Up @@ -167,7 +167,7 @@ public void doLogout(String accessToken) {
AdapterTokenStore tokenStore =
factory.createAdapterTokenStore(deployment, getRequest(), getResponse());
if (tokenStore != null) tokenStore.logout();
internalLogout(accessToken, request, response);
internalLogout(sessionId, request, response);
}

private void internalLogout(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ private void setLocation(String location) {
public void autofill(OAuth2Configuration conf) {
if (location != null) {
Map response = restTemplate.getForObject(this.location, Map.class);
assert response != null;
Optional.ofNullable(response.get(getAuthorizationEndpointAttrName()))
.ifPresent(uri -> conf.setAuthorizationUri((String) uri));
Optional.ofNullable(response.get(getTokenEndpointAttrName()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@
import java.util.Collections;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
Expand All @@ -55,6 +58,7 @@ public class OAuth2Configuration extends IdPConfiguration {
protected String authorizationUri;
protected String checkTokenEndpointUrl;
protected String logoutUri;
protected boolean globalLogoutEnabled = false;
protected String scopes;
protected String idTokenUri;
protected String discoveryUrl;
Expand Down Expand Up @@ -119,7 +123,7 @@ public String buildLoginUri(String accessType, String... additionalScopes) {
if (accessType != null) loginUri.append("&").append("access_type=").append(accessType);
String finalUrl = loginUri.toString();
if (LOGGER.isDebugEnabled())
LOGGER.info("Going to request authorization to this endpoint " + finalUrl);
LOGGER.info("Going to request authorization to this endpoint {}", finalUrl);
return finalUrl;
}

Expand Down Expand Up @@ -236,6 +240,20 @@ public void setLogoutUri(String logoutUri) {
this.logoutUri = logoutUri;
}

/** @return */
public boolean isGlobalLogoutEnabled() {
return globalLogoutEnabled;
}

/**
* Set th
*
* @param globalLogoutEnabled
*/
public void setGlobalLogoutEnabled(boolean globalLogoutEnabled) {
this.globalLogoutEnabled = globalLogoutEnabled;
}

/**
* Get the configured scopes as a String.
*
Expand Down Expand Up @@ -331,38 +349,85 @@ protected String appendParameters(MultiValueMap<String, String> params, String u
return builder.build().toUriString();
}

protected static void getLogoutRequestParams(
String token, String clientId, MultiValueMap<String, String> params) {
params.put("token", Collections.singletonList(token));
if (clientId != null && !clientId.isEmpty()) {
params.put("client_id", Collections.singletonList(clientId));
}
}

/**
* Build the revoke endpoint.
*
* @param token the access_token to revoke.
* @return the revoke endpoint.
*/
public Endpoint buildRevokeEndpoint(String token) {
public Endpoint buildRevokeEndpoint(
String token, String accessToken, OAuth2Configuration configuration) {
Endpoint result = null;
if (revokeEndpoint != null) {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.put("token", Collections.singletonList(token));
result = new Endpoint(HttpMethod.POST, appendParameters(params, revokeEndpoint));
HttpHeaders headers = getHttpHeaders(accessToken, configuration);

MultiValueMap<String, String> bodyParams = new LinkedMultiValueMap<>();
bodyParams.add("token", token);
bodyParams.add("client_id", clientId);

HttpEntity<MultiValueMap<String, String>> requestEntity =
new HttpEntity<>(bodyParams, headers);

result = new Endpoint(HttpMethod.POST, revokeEndpoint);
result.setRequestEntity(requestEntity);
}
return result;
}

private static HttpHeaders getHttpHeaders(
String accessToken, OAuth2Configuration configuration) {
HttpHeaders headers = getHeaders(accessToken, configuration);
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
return headers;
}

/**
* Build the logout endpoint.
*
* @param token the current access_token.
* @return the logout endpoint.
*/
public Endpoint buildLogoutEndpoint(String token) {
public Endpoint buildLogoutEndpoint(
String token, String accessToken, OAuth2Configuration configuration) {
Endpoint result = null;
if (logoutUri != null) {
HttpHeaders headers = getHeaders(accessToken, configuration);

MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.put("token", Collections.singletonList(token));
getLogoutRequestParams(token, clientId, params);

HttpEntity<MultiValueMap<String, String>> requestEntity =
new HttpEntity<>(null, headers);

result = new Endpoint(HttpMethod.GET, appendParameters(params, logoutUri));
result.setRequestEntity(requestEntity);
}
return result;
}

private static HttpHeaders getHeaders(String accessToken, OAuth2Configuration configuration) {
HttpHeaders headers = new HttpHeaders();
if (configuration != null
&& configuration.clientId != null
&& configuration.clientSecret != null)
headers.setBasicAuth(
configuration.clientId,
configuration
.clientSecret); // Set client ID and client secret for authentication
else if (accessToken != null) {
headers.set("Authorization", "Bearer " + accessToken);
}
return headers;
}

/** @return true if redirect to authorization is active always. False otherwise. */
public boolean isEnableRedirectEntryPoint() {
return enableRedirectEntryPoint;
Expand All @@ -383,7 +448,7 @@ public void setEnableRedirectEntryPoint(boolean enableRedirectEntryPoint) {
* @return the principal key.
*/
public String getPrincipalKey() {
if (principalKey == null || "".equals(principalKey)) return "email";
if (principalKey == null || principalKey.isEmpty()) return "email";
return principalKey;
}

Expand Down Expand Up @@ -428,13 +493,15 @@ public void setGroupsClaim(String groupsClaim) {
this.groupsClaim = groupsClaim;
}

/** Class the represent and endpoint with a HTTP method. */
/** Class the representing and endpoint with a HTTP method. */
public static class Endpoint {

private String url;

private HttpMethod method;

private HttpEntity<?> requestEntity;

public Endpoint(HttpMethod method, String url) {
this.method = method;
this.url = url;
Expand Down Expand Up @@ -467,5 +534,15 @@ public HttpMethod getMethod() {
public void setMethod(HttpMethod method) {
this.method = method;
}

/** @return */
public HttpEntity<?> getRequestEntity() {
return requestEntity;
}

/** @param requestEntity */
public void setRequestEntity(HttpEntity<?> requestEntity) {
this.requestEntity = requestEntity;
}
}
}
Loading

0 comments on commit 16bbce6

Please sign in to comment.