Skip to content

Commit bbc858c

Browse files
committed
[ELY-2534] OIDC logout support
1 parent 9a61d67 commit bbc858c

13 files changed

+311
-87
lines changed

http/oidc/src/main/java/org/wildfly/security/http/oidc/AuthenticationError.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,7 @@ public enum Reason {
3636
INVALID_TOKEN,
3737
STALE_TOKEN,
3838
NO_AUTHORIZATION_HEADER,
39-
NO_QUERY_PARAMETER_ACCESS_TOKEN,
40-
NO_SESSION_ID,
41-
METHOD_NOT_ALLOWED
39+
NO_QUERY_PARAMETER_ACCESS_TOKEN
4240
}
4341

4442
private Reason reason;

http/oidc/src/main/java/org/wildfly/security/http/oidc/ElytronMessages.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -279,11 +279,10 @@ interface ElytronMessages extends BasicLogger {
279279
@Message(id = 23070, value = "Authentication request format must be one of the following: oauth2, request, request_uri.")
280280
RuntimeException invalidAuthenticationRequestFormat();
281281

282-
@Message(id = 23071, value = "%s is not a valid value for %s")
282+
@Message(id = 23071, value = "Invalid logout output: %s is not a valid value for %s")
283283
RuntimeException invalidLogoutPath(String pathValue, String pathName);
284284

285-
@Message(id = 23072, value = "The end substring of %s: %s can not be identical to %s: %s")
286-
RuntimeException invalidLogoutCallbackPath(String callbackPathTitle, String callbacPathkValue,
287-
String logoutPathTitle, String logoutPathValue);
285+
@Message(id = 23072, value = "Invalid %s: %s the value must be an absolute URI")
286+
RuntimeException invalidLogoutCallbackPath(String callbackPathTitle, String callbackPathValue);
288287
}
289288

http/oidc/src/main/java/org/wildfly/security/http/oidc/LogoutHandler.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,13 @@
3838
*/
3939
final class LogoutHandler {
4040

41-
public static final String POST_LOGOUT_REDIRECT_URI_PARAM = "post_logout_redirect_uri";
42-
public static final String ID_TOKEN_HINT_PARAM = "id_token_hint";
41+
private static final String POST_LOGOUT_REDIRECT_URI_PARAM = "post_logout_redirect_uri";
42+
private static final String ID_TOKEN_HINT_PARAM = "id_token_hint";
4343
private static final String LOGOUT_TOKEN_PARAM = "logout_token";
4444
private static final String LOGOUT_TOKEN_TYPE = "Logout";
4545
private static final String CLIENT_ID_SID_SEPARATOR = "-";
46-
public static final String SID = "sid";
47-
public static final String ISS = "iss";
46+
private static final String SID = "sid";
47+
private static final String ISS = "iss";
4848

4949
/**
5050
* A bounded map to store sessions marked for invalidation after receiving logout requests through the back-channel
@@ -95,6 +95,7 @@ boolean tryLogout(OidcHttpFacade facade) {
9595
boolean isSessionMarkedForInvalidation(OidcHttpFacade facade) {
9696
HttpScope session = facade.getScope(Scope.SESSION);
9797
if (session == null || ! session.exists()) return false;
98+
9899
RefreshableOidcSecurityContext securityContext = (RefreshableOidcSecurityContext) session.getAttachment(OidcSecurityContext.class.getName());
99100
if (securityContext == null) {
100101
return false;
@@ -104,6 +105,7 @@ boolean isSessionMarkedForInvalidation(OidcHttpFacade facade) {
104105
if (idToken == null) {
105106
return false;
106107
}
108+
107109
return sessionsMarkedForInvalidation.remove(getSessionKey(facade, idToken.getSid())) != null;
108110
}
109111

@@ -116,10 +118,10 @@ private void redirectEndSessionEndpoint(OidcHttpFacade facade) {
116118
try {
117119
URIBuilder redirectUriBuilder = new URIBuilder(clientConfiguration.getEndSessionEndpointUrl())
118120
.addParameter(ID_TOKEN_HINT_PARAM, securityContext.getIDTokenString());
119-
String postLogoutPath = clientConfiguration.getPostLogoutPath();
120-
if (postLogoutPath != null) {
121-
redirectUriBuilder.addParameter(POST_LOGOUT_REDIRECT_URI_PARAM,
122-
getRedirectUri(facade) + postLogoutPath);
121+
String postLogoutUri = clientConfiguration.getPostLogoutUri();
122+
if (postLogoutUri != null) {
123+
log.trace("post_logout_redirect_uri: " + postLogoutUri);
124+
redirectUriBuilder.addParameter(POST_LOGOUT_REDIRECT_URI_PARAM, postLogoutUri);
123125
}
124126

125127
logoutUri = redirectUriBuilder.build().toString();

http/oidc/src/main/java/org/wildfly/security/http/oidc/Oidc.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ public class Oidc {
175175
public static final String PROVIDER_URL = "provider-url";
176176
public static final String LOGOUT_PATH = "logout-path";
177177
public static final String LOGOUT_CALLBACK_PATH = "logout-callback-path";
178-
public static final String POST_LOGOUT_PATH = "post-logout-path";
178+
public static final String POST_LOGOUT_URI = "post-logout-uri";
179179
public static final String LOGOUT_SESSION_REQUIRED = "logout-session-required";
180180

181181
/**

http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcClientConfiguration.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,9 @@ public enum RelativeUrlsUsed {
143143
protected String requestObjectSigningKeyAlias;
144144
protected String requestObjectSigningKeyStoreType;
145145
protected JWKEncPublicKeyLocator encryptionPublicKeyLocator;
146-
private boolean logoutSessionRequired = true;
146+
private String logoutSessionRequired;
147147

148-
private String postLogoutPath;
148+
private String postLogoutUri;
149149
private boolean sessionRequiredOnLogout = true;
150150
private String logoutPath = "/logout";
151151
private String logoutCallbackPath = "/logout/callback";
@@ -808,19 +808,19 @@ public JWKEncPublicKeyLocator getEncryptionPublicKeyLocator() {
808808
return this.encryptionPublicKeyLocator;
809809
}
810810

811-
public void setPostLogoutPath(String postLogoutPath) {
812-
this.postLogoutPath = postLogoutPath;
811+
public void setPostLogoutUri(String postLogoutUri) {
812+
this.postLogoutUri = postLogoutUri;
813813
}
814814

815-
public String getPostLogoutPath() {
816-
return postLogoutPath;
815+
public String getPostLogoutUri() {
816+
return postLogoutUri;
817817
}
818818

819-
public boolean isLogoutSessionRequired() {
819+
public String getLogoutSessionRequired() {
820820
return logoutSessionRequired;
821821
}
822822

823-
public void setLogoutSessionRequired(boolean logoutSessionRequired) {
823+
public void setLogoutSessionRequired(String logoutSessionRequired) {
824824
this.logoutSessionRequired = logoutSessionRequired;
825825
}
826826

http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcClientConfigurationBuilder.java

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
import static org.wildfly.security.http.oidc.Oidc.TokenStore;
2828
import static org.wildfly.security.http.oidc.Oidc.LOGOUT_PATH;
2929
import static org.wildfly.security.http.oidc.Oidc.LOGOUT_CALLBACK_PATH;
30-
import static org.wildfly.security.http.oidc.Oidc.POST_LOGOUT_PATH;
30+
import static org.wildfly.security.http.oidc.Oidc.POST_LOGOUT_URI;
3131
import static org.wildfly.security.http.oidc.Oidc.LOGOUT_SESSION_REQUIRED;
3232

3333
import java.io.IOException;
@@ -199,7 +199,10 @@ protected OidcClientConfiguration internalBuild(final OidcJsonConfiguration oidc
199199

200200
oidcClientConfiguration.setTokenSignatureAlgorithm(oidcJsonConfiguration.getTokenSignatureAlgorithm());
201201

202-
String tmpLogoutPath = System.getProperty(LOGOUT_PATH);
202+
String tmpLogoutPath = oidcJsonConfiguration.getLogoutPath();
203+
if (tmpLogoutPath == null) {
204+
tmpLogoutPath = System.getProperty(LOGOUT_PATH);
205+
}
203206
log.debug("sysProp LOGOUT_PATH: " + (tmpLogoutPath == null ? "NULL" : tmpLogoutPath));
204207
if (tmpLogoutPath != null) {
205208
if (isValidPath(tmpLogoutPath)) {
@@ -209,38 +212,42 @@ protected OidcClientConfiguration internalBuild(final OidcJsonConfiguration oidc
209212
}
210213
}
211214

212-
213-
String tmpLogoutCallbackPath = System.getProperty(LOGOUT_CALLBACK_PATH);
215+
String tmpLogoutCallbackPath = oidcJsonConfiguration.getLogoutCallbackPath();
216+
if (tmpLogoutCallbackPath == null) {
217+
tmpLogoutCallbackPath = System.getProperty(LOGOUT_CALLBACK_PATH);
218+
}
214219
log.debug("sysProp LOGOUT_CALLBACK_PATH: " + (tmpLogoutCallbackPath == null ? "NULL" : tmpLogoutCallbackPath));
215220
if (tmpLogoutCallbackPath != null) {
216-
if (isValidPath(tmpLogoutCallbackPath)
217-
&& !tmpLogoutCallbackPath.endsWith(oidcClientConfiguration.getLogoutPath())) {
221+
if (tmpLogoutCallbackPath.startsWith("http")) {
218222
oidcClientConfiguration.setLogoutCallbackPath(tmpLogoutCallbackPath);
219223
} else {
220-
if (!isValidPath(tmpLogoutCallbackPath)) {
221-
throw log.invalidLogoutPath(tmpLogoutPath, LOGOUT_CALLBACK_PATH);
222-
} else {
223-
throw log.invalidLogoutCallbackPath(LOGOUT_CALLBACK_PATH, tmpLogoutCallbackPath,
224-
LOGOUT_PATH, oidcClientConfiguration.getLogoutPath());
225-
}
224+
throw log.invalidLogoutCallbackPath(LOGOUT_CALLBACK_PATH, tmpLogoutCallbackPath);
226225
}
227226
}
228227

229-
String tmpPostLogoutPath = System.getProperty(POST_LOGOUT_PATH);
230-
log.debug("sysProp POST_LOGOUT_PATH: " + (tmpPostLogoutPath == null ? "NULL" : tmpPostLogoutPath));
231-
if (tmpPostLogoutPath != null) {
232-
if (isValidPath(tmpPostLogoutPath)) {
233-
oidcClientConfiguration.setPostLogoutPath(tmpPostLogoutPath);
228+
String tmpPostLogoutUri = oidcJsonConfiguration.getPostLogoutUri();
229+
if (tmpPostLogoutUri == null) {
230+
tmpPostLogoutUri = System.getProperty(POST_LOGOUT_URI);
231+
}
232+
log.debug("sysProp POST_LOGOUT_URI: " + (tmpPostLogoutUri == null ? "NULL" : tmpPostLogoutUri));
233+
if (tmpPostLogoutUri != null) {
234+
if (tmpPostLogoutUri.startsWith("http")) {
235+
oidcClientConfiguration.setPostLogoutUri(tmpPostLogoutUri);
234236
} else {
235-
throw log.invalidLogoutPath(tmpLogoutPath, POST_LOGOUT_PATH);
237+
throw log.invalidLogoutPath(tmpPostLogoutUri, POST_LOGOUT_URI);
236238
}
237239
}
238240

239-
String tmpLogoutSessionRequired = System.getProperty(LOGOUT_SESSION_REQUIRED);
240-
if (tmpLogoutSessionRequired != null) {
241-
oidcClientConfiguration.setLogoutSessionRequired(
242-
Boolean.valueOf(tmpLogoutSessionRequired));
241+
String tmpLogoutSessionRequired = oidcJsonConfiguration.getLogoutSessionRequired();
242+
if (tmpLogoutSessionRequired == null) {
243+
String sysPropLogoutSessionRequired = System.getProperty(LOGOUT_SESSION_REQUIRED);
244+
if (sysPropLogoutSessionRequired == null) {
245+
tmpLogoutSessionRequired = "true";
246+
} else {
247+
tmpLogoutSessionRequired = sysPropLogoutSessionRequired;
248+
}
243249
}
250+
oidcClientConfiguration.setLogoutSessionRequired(tmpLogoutSessionRequired);
244251

245252
return oidcClientConfiguration;
246253
}

http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcHttpFacade.java

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -550,21 +550,4 @@ public String getPath() {
550550
return path;
551551
}
552552
}
553-
554-
// rls debug only
555-
public String rlsGetSessionIds() {
556-
Collection<String> sessions = request.getScopeIds(Scope.SESSION);
557-
if (sessions == null) {
558-
return "## OidcHttpFacade Scope.SESSION sessionIds is null.";
559-
} else if (sessions.isEmpty()){
560-
return "Scope.SESSION sessionIds is empty.";
561-
}
562-
StringBuffer sb = new StringBuffer();
563-
sb.append("Scope.SESSION sessionIds: [");
564-
for (String s : sessions) {
565-
sb.append(s + ", ");
566-
}
567-
sb.append("]\n");
568-
return sb.toString();
569-
}
570553
}

http/oidc/src/main/java/org/wildfly/security/http/oidc/OidcJsonConfiguration.java

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@
4343
import static org.wildfly.security.http.oidc.Oidc.ENABLE_PKCE;
4444
import static org.wildfly.security.http.oidc.Oidc.EXPOSE_TOKEN;
4545
import static org.wildfly.security.http.oidc.Oidc.IGNORE_OAUTH_QUERY_PARAMETER;
46+
import static org.wildfly.security.http.oidc.Oidc.LOGOUT_PATH;
47+
import static org.wildfly.security.http.oidc.Oidc.LOGOUT_CALLBACK_PATH;
48+
import static org.wildfly.security.http.oidc.Oidc.LOGOUT_SESSION_REQUIRED;
4649
import static org.wildfly.security.http.oidc.Oidc.MIN_TIME_BETWEEN_JWKS_REQUESTS;
50+
import static org.wildfly.security.http.oidc.Oidc.POST_LOGOUT_URI;
4751
import static org.wildfly.security.http.oidc.Oidc.PRINCIPAL_ATTRIBUTE;
4852
import static org.wildfly.security.http.oidc.Oidc.PROVIDER_URL;
4953
import static org.wildfly.security.http.oidc.Oidc.PROXY_URL;
@@ -99,8 +103,9 @@
99103
ALWAYS_REFRESH_TOKEN,
100104
REGISTER_NODE_AT_STARTUP, REGISTER_NODE_PERIOD, TOKEN_STORE, ADAPTER_STATE_COOKIE_PATH, PRINCIPAL_ATTRIBUTE,
101105
PROXY_URL, TURN_OFF_CHANGE_SESSION_ID_ON_LOGIN, TOKEN_MINIMUM_TIME_TO_LIVE,
102-
MIN_TIME_BETWEEN_JWKS_REQUESTS, PUBLIC_KEY_CACHE_TTL,
103-
IGNORE_OAUTH_QUERY_PARAMETER, VERIFY_TOKEN_AUDIENCE, TOKEN_SIGNATURE_ALGORITHM, SCOPE,
106+
MIN_TIME_BETWEEN_JWKS_REQUESTS, POST_LOGOUT_URI, PUBLIC_KEY_CACHE_TTL,
107+
IGNORE_OAUTH_QUERY_PARAMETER, LOGOUT_PATH, LOGOUT_CALLBACK_PATH, LOGOUT_SESSION_REQUIRED,
108+
VERIFY_TOKEN_AUDIENCE, TOKEN_SIGNATURE_ALGORITHM, SCOPE,
104109
AUTHENTICATION_REQUEST_FORMAT, REQUEST_OBJECT_SIGNING_ALGORITHM, REQUEST_OBJECT_ENCRYPTION_ALG_VALUE,
105110
REQUEST_OBJECT_ENCRYPTION_ENC_VALUE, REQUEST_OBJECT_SIGNING_KEYSTORE_FILE,
106111
REQUEST_OBJECT_SIGNING_KEYSTORE_PASSWORD,REQUEST_OBJECT_SIGNING_KEY_PASSWORD, REQUEST_OBJECT_SIGNING_KEY_ALIAS,
@@ -152,13 +157,21 @@ public class OidcJsonConfiguration {
152157
protected int tokenMinimumTimeToLive = 0;
153158
@JsonProperty(MIN_TIME_BETWEEN_JWKS_REQUESTS)
154159
protected int minTimeBetweenJwksRequests = 10;
160+
@JsonProperty(POST_LOGOUT_URI)
161+
protected String postLogoutUri;
155162
@JsonProperty(PUBLIC_KEY_CACHE_TTL)
156163
protected int publicKeyCacheTtl = 86400; // 1 day
157164
// https://tools.ietf.org/html/rfc7636
158165
@JsonProperty(ENABLE_PKCE)
159166
protected boolean pkce = false;
160167
@JsonProperty(IGNORE_OAUTH_QUERY_PARAMETER)
161168
protected boolean ignoreOAuthQueryParameter = false;
169+
@JsonProperty(LOGOUT_PATH)
170+
protected String logoutPath;
171+
@JsonProperty(LOGOUT_CALLBACK_PATH)
172+
protected String logoutCallbackPath;
173+
@JsonProperty(LOGOUT_SESSION_REQUIRED)
174+
protected String logoutSessionRequired;
162175
@JsonProperty(VERIFY_TOKEN_AUDIENCE)
163176
protected boolean verifyTokenAudience = false;
164177
@JsonProperty(CONFIDENTIAL_PORT)
@@ -407,6 +420,14 @@ public int getMinTimeBetweenJwksRequests() {
407420
return minTimeBetweenJwksRequests;
408421
}
409422

423+
public String getPostLogoutUri() {
424+
return postLogoutUri;
425+
}
426+
427+
public void setPostLogoutUri(String postLogoutUri) {
428+
this.postLogoutUri = postLogoutUri;
429+
}
430+
410431
public void setMinTimeBetweenJwksRequests(int minTimeBetweenJwksRequests) {
411432
this.minTimeBetweenJwksRequests = minTimeBetweenJwksRequests;
412433
}
@@ -436,6 +457,30 @@ public void setIgnoreOAuthQueryParameter(boolean ignoreOAuthQueryParameter) {
436457
this.ignoreOAuthQueryParameter = ignoreOAuthQueryParameter;
437458
}
438459

460+
public String getLogoutPath() {
461+
return logoutPath;
462+
}
463+
464+
public void setLogoutPath(String logoutPath) {
465+
this.logoutPath = logoutPath;
466+
}
467+
468+
public String getLogoutCallbackPath() {
469+
return logoutCallbackPath;
470+
}
471+
472+
public void setLogoutCallbackPath(String logoutCallbackPath) {
473+
this.logoutCallbackPath = logoutCallbackPath;
474+
}
475+
476+
public String getLogoutSessionRequired() {
477+
return logoutSessionRequired;
478+
}
479+
480+
public void setLogoutSessionRequired(String logoutSessionRequired) {
481+
this.logoutSessionRequired = logoutSessionRequired;
482+
}
483+
439484
public boolean isVerifyTokenAudience() {
440485
return verifyTokenAudience;
441486
}

http/oidc/src/main/java/org/wildfly/security/http/oidc/RefreshableOidcSecurityContext.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,6 @@ public boolean refreshToken(boolean checkActive) {
112112
}
113113
if (isActive() && isTokenTimeToLiveSufficient(this.token)) return true;
114114
}
115-
116115
if (this.clientConfiguration == null || refreshToken == null) return false;
117116

118117
if (log.isTraceEnabled()) {

http/oidc/src/main/java/org/wildfly/security/http/oidc/RequestAuthenticator.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ public RequestAuthenticator(OidcHttpFacade facade, OidcClientConfiguration deplo
5555
public AuthOutcome authenticate() {
5656
AuthOutcome authenticate = doAuthenticate();
5757
if (AuthOutcome.AUTHENTICATED.equals(authenticate) && !facade.isAuthorized()) {
58-
log.trace("## RequestAutenticator.authenticate AUTHENTICATED but NOT Autorized");
5958
return AuthOutcome.FAILED;
6059
}
6160
return authenticate;

0 commit comments

Comments
 (0)