change logout behavior
This commit is contained in:
parent
b96f8aef6d
commit
dc4e8603d7
17 changed files with 225 additions and 96 deletions
|
@ -12,6 +12,7 @@
|
|||
<!ENTITY JBossAdapter SYSTEM "modules/jboss-adapter.xml">
|
||||
<!ENTITY JavascriptAdapter SYSTEM "modules/javascript-adapter.xml">
|
||||
<!ENTITY InstalledApplications SYSTEM "modules/installed-applications.xml">
|
||||
<!ENTITY Logout SYSTEM "modules/logout.xml">
|
||||
<!ENTITY SocialConfig SYSTEM "modules/social-config.xml">
|
||||
<!ENTITY SocialFacebook SYSTEM "modules/social-facebook.xml">
|
||||
<!ENTITY SocialGitHub SYSTEM "modules/social-github.xml">
|
||||
|
@ -80,6 +81,7 @@ This one is short
|
|||
&JBossAdapter;
|
||||
&JavascriptAdapter;
|
||||
&InstalledApplications;
|
||||
&Logout;
|
||||
</chapter>
|
||||
|
||||
<chapter>
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
<chapter id="Migration_from_older_versions">
|
||||
<title>Migration from older versions</title>
|
||||
<sect1>
|
||||
<title>Migrating from 1.0 Beta 4 to RC-1</title>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
logout REST API has been refactored. The GET request on the logout URI does not take a session_state
|
||||
parameter anymore. You must be logged in in order to log out the session.
|
||||
You can also POST to the lougt REST URI. This action requires a valid refresh token to perform the logout.
|
||||
The signature is the same as refresh token minus the grant type form parameter. See documentation for details.
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect1>
|
||||
<sect1>
|
||||
<title>Migrating from 1.0 Beta 1 to Beta 4</title>
|
||||
<itemizedlist>
|
||||
|
|
|
@ -88,7 +88,7 @@ try {
|
|||
if (isPublic()) { // if client is public access type
|
||||
formparams.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ID, "customer-portal"));
|
||||
} else {
|
||||
String authorization = BasicAuthHelper.createHeader("customer-portal", "secret-secret-secret);
|
||||
String authorization = BasicAuthHelper.createHeader("customer-portal", "secret-secret-secret");
|
||||
post.setHeader("Authorization", authorization);
|
||||
}
|
||||
UrlEncodedFormEntity form = new UrlEncodedFormEntity(formparams, "UTF-8");
|
||||
|
@ -125,4 +125,36 @@ GET /my/rest/api
|
|||
Authorization: Bearer 2YotnFZFEjr1zCsicMWpAA
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
To logout you must use the refresh token contained in the AccessTokenResponse object.
|
||||
</para>
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
|
||||
if (isPublic()) { // if client is public access type
|
||||
formparams.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ID, "customer-portal"));
|
||||
} else {
|
||||
String authorization = BasicAuthHelper.createHeader("customer-portal", "secret-secret-secret");
|
||||
post.setHeader("Authorization", authorization);
|
||||
}
|
||||
formparams.add(new BasicNameValuePair(OAuth2Constants.REFRESH_TOKEN, tokenResponse.getRefreshToken()));
|
||||
HttpResponse response = null;
|
||||
URI logoutUri = KeycloakUriBuilder.fromUri(getBaseUrl(request) + "/auth")
|
||||
.path(ServiceUrlConstants.TOKEN_SERVICE_LOGOUT_PATH)
|
||||
.build("demo");
|
||||
HttpPost post = new HttpPost(logoutUri);
|
||||
UrlEncodedFormEntity form = new UrlEncodedFormEntity(formparams, "UTF-8");
|
||||
post.setEntity(form);
|
||||
response = client.execute(post);
|
||||
int status = response.getStatusLine().getStatusCode();
|
||||
HttpEntity entity = response.getEntity();
|
||||
if (status != 204) {
|
||||
error(status, entity);
|
||||
}
|
||||
if (entity == null) {
|
||||
return;
|
||||
}
|
||||
InputStream is = entity.getContent();
|
||||
if (is != null) is.close();
|
||||
]]></programlisting>
|
||||
</chapter>
|
9
docbook/reference/en/en-US/modules/logout.xml
Executable file
9
docbook/reference/en/en-US/modules/logout.xml
Executable file
|
@ -0,0 +1,9 @@
|
|||
<section>
|
||||
<title>Logout</title>
|
||||
<para>
|
||||
There are multiple ways you can logout from a web application. For Java EE servlet containers, you can call
|
||||
HttpServletRequest.logout().
|
||||
For any other browser application, you can point the browser at the url <literal>http://auth-server/auth/realms/{realm-name}/tokens/logout?redirect_uri=encodedRedirectUri</literal>.
|
||||
This will log you out if you have an SSO session with your browser.
|
||||
</para>
|
||||
</section>
|
|
@ -102,17 +102,23 @@ public class AdminClient {
|
|||
|
||||
|
||||
try {
|
||||
HttpGet get = new HttpGet(KeycloakUriBuilder.fromUri(getBaseUrl(request) + "/auth")
|
||||
HttpPost post = new HttpPost(KeycloakUriBuilder.fromUri(getBaseUrl(request) + "/auth")
|
||||
.path(ServiceUrlConstants.TOKEN_SERVICE_LOGOUT_PATH)
|
||||
.queryParam("session_state", res.getSessionState())
|
||||
.build("demo"));
|
||||
HttpResponse response = client.execute(get);
|
||||
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
|
||||
formparams.add(new BasicNameValuePair(OAuth2Constants.REFRESH_TOKEN, res.getRefreshToken()));
|
||||
formparams.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ID, "admin-client"));
|
||||
HttpResponse response = client.execute(post);
|
||||
boolean status = response.getStatusLine().getStatusCode() != 204;
|
||||
HttpEntity entity = response.getEntity();
|
||||
if (entity == null) {
|
||||
return;
|
||||
}
|
||||
InputStream is = entity.getContent();
|
||||
if (is != null) is.close();
|
||||
if (status) {
|
||||
throw new RuntimeException("failed to logout");
|
||||
}
|
||||
} finally {
|
||||
client.getConnectionManager().shutdown();
|
||||
}
|
||||
|
|
|
@ -42,6 +42,14 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext
|
|||
return super.getTokenString();
|
||||
}
|
||||
|
||||
public void logout(KeycloakDeployment deployment) {
|
||||
try {
|
||||
ServerRequest.invokeLogout(deployment, refreshToken);
|
||||
} catch (Exception e) {
|
||||
log.error("failed to invoke remote logout", e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return this.token.isActive() && this.token.getIssuedAt() > deployment.getNotBefore();
|
||||
}
|
||||
|
|
|
@ -48,19 +48,41 @@ public class ServerRequest {
|
|||
}
|
||||
}
|
||||
|
||||
public static void invokeLogout(KeycloakDeployment deployment, String sessionId) throws IOException, HttpFailure {
|
||||
URI uri = deployment.getLogoutUrl().clone().queryParam("session_state", sessionId).build();
|
||||
HttpGet logout = new HttpGet(uri);
|
||||
HttpResponse response = deployment.getClient().execute(logout);
|
||||
public static void invokeLogout(KeycloakDeployment deployment, String refreshToken) throws IOException, HttpFailure {
|
||||
String client_id = deployment.getResourceName();
|
||||
Map<String, String> credentials = deployment.getResourceCredentials();
|
||||
HttpClient client = deployment.getClient();
|
||||
URI uri = deployment.getLogoutUrl().clone().build();
|
||||
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
|
||||
for (Map.Entry<String, String> entry : credentials.entrySet()) {
|
||||
formparams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
formparams.add(new BasicNameValuePair(OAuth2Constants.REFRESH_TOKEN, refreshToken));
|
||||
HttpResponse response = null;
|
||||
HttpPost post = new HttpPost(uri);
|
||||
if (!deployment.isPublicClient()) {
|
||||
String clientSecret = credentials.get(CredentialRepresentation.SECRET);
|
||||
if (clientSecret != null) {
|
||||
String authorization = BasicAuthHelper.createHeader(client_id, clientSecret);
|
||||
post.setHeader("Authorization", authorization);
|
||||
}
|
||||
} else {
|
||||
formparams.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ID, client_id));
|
||||
}
|
||||
|
||||
UrlEncodedFormEntity form = new UrlEncodedFormEntity(formparams, "UTF-8");
|
||||
post.setEntity(form);
|
||||
response = client.execute(post);
|
||||
int status = response.getStatusLine().getStatusCode();
|
||||
HttpEntity entity = response.getEntity();
|
||||
if (status != 200) {
|
||||
if (status != 204) {
|
||||
error(status, entity);
|
||||
}
|
||||
if (entity == null) {
|
||||
return;
|
||||
}
|
||||
entity.getContent().close();
|
||||
InputStream is = entity.getContent();
|
||||
if (is != null) is.close();
|
||||
}
|
||||
|
||||
public static AccessTokenResponse invokeAccessCodeToToken(KeycloakDeployment deployment, String code, String redirectUri) throws HttpFailure, IOException {
|
||||
|
|
|
@ -64,10 +64,8 @@ public class KeycloakAuthenticatorValve extends FormAuthenticator implements Lif
|
|||
Session session = request.getSessionInternal(false);
|
||||
if (session != null) {
|
||||
session.removeNote(KeycloakSecurityContext.class.getName());
|
||||
try {
|
||||
ServerRequest.invokeLogout(deploymentContext.getDeployment(), ksc.getToken().getSessionState());
|
||||
} catch (Exception e) {
|
||||
log.error("failed to invoke remote logout", e);
|
||||
if (ksc instanceof RefreshableKeycloakSecurityContext) {
|
||||
((RefreshableKeycloakSecurityContext)ksc).logout(deploymentContext.getDeployment());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,11 +81,8 @@ public class ServletKeycloakAuthMech extends UndertowKeycloakAuthMech {
|
|||
if (account == null) return;
|
||||
session.removeAttribute(KeycloakSecurityContext.class.getName());
|
||||
session.removeAttribute(KeycloakUndertowAccount.class.getName());
|
||||
String sessionId = account.getKeycloakSecurityContext().getToken().getSessionState();
|
||||
try {
|
||||
ServerRequest.invokeLogout(deploymentContext.getDeployment(), sessionId);
|
||||
} catch (Exception e) {
|
||||
log.error("failed to invoke remote logout", e);
|
||||
if (account.getKeycloakSecurityContext() != null) {
|
||||
account.getKeycloakSecurityContext().logout(deploymentContext.getDeployment());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -72,11 +72,8 @@ public abstract class UndertowKeycloakAuthMech implements AuthenticationMechanis
|
|||
KeycloakUndertowAccount account = (KeycloakUndertowAccount)session.getAttribute(KeycloakUndertowAccount.class.getName());
|
||||
if (account == null) return;
|
||||
session.removeAttribute(KeycloakUndertowAccount.class.getName());
|
||||
String sessionId = account.getKeycloakSecurityContext().getToken().getSessionState();
|
||||
try {
|
||||
ServerRequest.invokeLogout(deploymentContext.getDeployment(), sessionId);
|
||||
} catch (Exception e) {
|
||||
log.error("failed to invoke remote logout", e);
|
||||
if (account.getKeycloakSecurityContext() != null) {
|
||||
account.getKeycloakSecurityContext().logout(deploymentContext.getDeployment());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -64,23 +64,7 @@ public class TokenManager {
|
|||
}
|
||||
|
||||
public AccessToken refreshAccessToken(KeycloakSession session, UriInfo uriInfo, ClientConnection connection, RealmModel realm, ClientModel client, String encodedRefreshToken, Audit audit) throws OAuthErrorException {
|
||||
JWSInput jws = new JWSInput(encodedRefreshToken);
|
||||
RefreshToken refreshToken = null;
|
||||
try {
|
||||
if (!RSAProvider.verify(jws, realm.getPublicKey())) {
|
||||
throw new RuntimeException("Invalid refresh token");
|
||||
}
|
||||
refreshToken = jws.readJsonContent(RefreshToken.class);
|
||||
} catch (IOException e) {
|
||||
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid refresh token", e);
|
||||
}
|
||||
if (refreshToken.isExpired()) {
|
||||
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Refresh token expired");
|
||||
}
|
||||
|
||||
if (refreshToken.getIssuedAt() < realm.getNotBefore()) {
|
||||
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Stale refresh token");
|
||||
}
|
||||
RefreshToken refreshToken = verifyRefreshToken(realm, encodedRefreshToken);
|
||||
|
||||
audit.user(refreshToken.getSubject()).session(refreshToken.getSessionState()).detail(Details.REFRESH_TOKEN_ID, refreshToken.getId());
|
||||
|
||||
|
@ -122,6 +106,27 @@ public class TokenManager {
|
|||
return accessToken;
|
||||
}
|
||||
|
||||
public RefreshToken verifyRefreshToken(RealmModel realm, String encodedRefreshToken) throws OAuthErrorException {
|
||||
JWSInput jws = new JWSInput(encodedRefreshToken);
|
||||
RefreshToken refreshToken = null;
|
||||
try {
|
||||
if (!RSAProvider.verify(jws, realm.getPublicKey())) {
|
||||
throw new RuntimeException("Invalid refresh token");
|
||||
}
|
||||
refreshToken = jws.readJsonContent(RefreshToken.class);
|
||||
} catch (IOException e) {
|
||||
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid refresh token", e);
|
||||
}
|
||||
if (refreshToken.isExpired()) {
|
||||
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Refresh token expired");
|
||||
}
|
||||
|
||||
if (refreshToken.getIssuedAt() < realm.getNotBefore()) {
|
||||
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Stale refresh token");
|
||||
}
|
||||
return refreshToken;
|
||||
}
|
||||
|
||||
public AccessToken createClientAccessToken(Set<RoleModel> requestedRoles, RealmModel realm, ClientModel client, UserModel user, UserSessionModel session) {
|
||||
AccessToken token = initToken(realm, client, user, session);
|
||||
for (RoleModel role : requestedRoles) {
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.keycloak.models.UserSessionModel;
|
|||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.AccessTokenResponse;
|
||||
import org.keycloak.representations.RefreshToken;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
import org.keycloak.ClientConnection;
|
||||
import org.keycloak.services.managers.AccessCode;
|
||||
|
@ -1040,39 +1041,29 @@ public class TokenService {
|
|||
}
|
||||
|
||||
/**
|
||||
* Logout user session.
|
||||
* Logout user session. User must be logged in via a session cookie.
|
||||
*
|
||||
* @param sessionState
|
||||
* @param redirectUri
|
||||
* @return
|
||||
*/
|
||||
@Path("logout")
|
||||
@GET
|
||||
@NoCache
|
||||
public Response logout(final @QueryParam("session_state") String sessionState, final @QueryParam("redirect_uri") String redirectUri) {
|
||||
public Response logout(final @QueryParam("redirect_uri") String redirectUri) {
|
||||
// todo do we care if anybody can trigger this?
|
||||
|
||||
audit.event(EventType.LOGOUT);
|
||||
if (redirectUri != null) {
|
||||
audit.detail(Details.REDIRECT_URI, redirectUri);
|
||||
}
|
||||
if (sessionState != null) {
|
||||
audit.session(sessionState);
|
||||
}
|
||||
|
||||
// authenticate identity cookie, but ignore an access token timeout as we're logging out anyways.
|
||||
AuthenticationManager.AuthResult authResult = authManager.authenticateIdentityCookie(session, realm, uriInfo, clientConnection, headers, false);
|
||||
if (authResult != null) {
|
||||
logout(authResult.getSession());
|
||||
} else if (sessionState != null) {
|
||||
UserSessionModel userSession = session.sessions().getUserSession(realm, sessionState);
|
||||
if (userSession != null) {
|
||||
logout(userSession);
|
||||
} else {
|
||||
audit.error(Errors.USER_SESSION_NOT_FOUND);
|
||||
}
|
||||
} else {
|
||||
audit.error(Errors.USER_NOT_LOGGED_IN);
|
||||
OAuthFlows oauth = Flows.oauth(session, realm, request, uriInfo, clientConnection, authManager, tokenManager);
|
||||
return oauth.forwardToSecurityFailure("Not logged in.");
|
||||
}
|
||||
|
||||
if (redirectUri != null) {
|
||||
|
@ -1088,6 +1079,61 @@ public class TokenService {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout a session via a non-browser invocation. Similar signature to refresh token except there is no grant_type.
|
||||
* You must pass in the refresh token and
|
||||
* authenticate the client if it is not public.
|
||||
*
|
||||
* If the client is a confidential client
|
||||
* you must include the client-id (application name or oauth client name) and secret in an Basic Auth Authorization header.
|
||||
*
|
||||
* If the client is a public client, then you must include a "client_id" form parameter with the app's or oauth client's name.
|
||||
*
|
||||
* returns 204 if successful, 400 if not with a json error response.
|
||||
*
|
||||
* @param authorizationHeader
|
||||
* @param form
|
||||
* @return
|
||||
*/
|
||||
@Path("logout")
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
public Response logoutToken(final @HeaderParam(HttpHeaders.AUTHORIZATION) String authorizationHeader,
|
||||
final MultivaluedMap<String, String> form) {
|
||||
logger.info("--> logoutToken");
|
||||
if (!checkSsl()) {
|
||||
throw new NotAcceptableException("HTTPS required");
|
||||
}
|
||||
|
||||
audit.event(EventType.LOGOUT);
|
||||
|
||||
ClientModel client = authorizeClient(authorizationHeader, form, audit);
|
||||
String refreshToken = form.getFirst(OAuth2Constants.REFRESH_TOKEN);
|
||||
if (refreshToken == null) {
|
||||
Map<String, String> error = new HashMap<String, String>();
|
||||
error.put(OAuth2Constants.ERROR, OAuthErrorException.INVALID_REQUEST);
|
||||
error.put(OAuth2Constants.ERROR_DESCRIPTION, "No refresh token");
|
||||
audit.error(Errors.INVALID_TOKEN);
|
||||
logger.error("OAuth Error: no refresh token");
|
||||
return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
|
||||
}
|
||||
try {
|
||||
RefreshToken token = tokenManager.verifyRefreshToken(realm, refreshToken);
|
||||
UserSessionModel userSessionModel = session.sessions().getUserSession(realm, token.getSessionState());
|
||||
if (userSessionModel != null) {
|
||||
logout(userSessionModel);
|
||||
}
|
||||
} catch (OAuthErrorException e) {
|
||||
Map<String, String> error = new HashMap<String, String>();
|
||||
error.put(OAuth2Constants.ERROR, e.getError());
|
||||
if (e.getDescription() != null) error.put(OAuth2Constants.ERROR_DESCRIPTION, e.getDescription());
|
||||
audit.error(Errors.INVALID_TOKEN);
|
||||
logger.error("OAuth Error", e);
|
||||
return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
|
||||
}
|
||||
return Cors.add(request, Response.noContent()).auth().allowedOrigins(client).allowedMethods("POST").exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS).build();
|
||||
}
|
||||
|
||||
private void logout(UserSessionModel userSession) {
|
||||
authManager.logout(session, realm, userSession, uriInfo, clientConnection);
|
||||
audit.user(userSession.getUser()).session(userSession).success();
|
||||
|
|
|
@ -171,11 +171,31 @@ public class OAuthClient {
|
|||
return new AccessTokenResponse(client.execute(post));
|
||||
}
|
||||
|
||||
public HttpResponse doLogout(String redirectUri, String sessionState) throws IOException {
|
||||
public HttpResponse doLogout(String refreshToken, String clientSecret) throws IOException {
|
||||
HttpClient client = new DefaultHttpClient();
|
||||
HttpGet get = new HttpGet(getLogoutUrl(redirectUri, sessionState));
|
||||
HttpPost post = new HttpPost(getLogoutUrl(null, null));
|
||||
|
||||
return client.execute(get);
|
||||
List<NameValuePair> parameters = new LinkedList<NameValuePair>();
|
||||
if (refreshToken != null) {
|
||||
parameters.add(new BasicNameValuePair(OAuth2Constants.REFRESH_TOKEN, refreshToken));
|
||||
}
|
||||
if (clientId != null && clientSecret != null) {
|
||||
String authorization = BasicAuthHelper.createHeader(clientId, clientSecret);
|
||||
post.setHeader("Authorization", authorization);
|
||||
}
|
||||
else if (clientId != null) {
|
||||
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ID, clientId));
|
||||
}
|
||||
|
||||
UrlEncodedFormEntity formEntity;
|
||||
try {
|
||||
formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
post.setEntity(formEntity);
|
||||
|
||||
return client.execute(post);
|
||||
}
|
||||
|
||||
public AccessTokenResponse doRefreshTokenRequest(String refreshToken, String password) {
|
||||
|
|
|
@ -214,7 +214,8 @@ public class AdapterTest {
|
|||
|
||||
|
||||
driver.navigate().to("http://localhost:8081/customer-portal");
|
||||
Assert.assertTrue(driver.getCurrentUrl().startsWith(LOGIN_URL));
|
||||
String currentUrl = driver.getCurrentUrl();
|
||||
Assert.assertTrue(currentUrl.startsWith(LOGIN_URL));
|
||||
driver.navigate().to("http://localhost:8081/product-portal");
|
||||
Assert.assertTrue(driver.getCurrentUrl().startsWith(LOGIN_URL));
|
||||
|
||||
|
|
30
testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LogoutTest.java
Normal file → Executable file
30
testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LogoutTest.java
Normal file → Executable file
|
@ -124,32 +124,15 @@ public class LogoutTest {
|
|||
|
||||
String sessionId = events.expectLogin().assertEvent().getSessionId();
|
||||
|
||||
// Login session 2
|
||||
WebDriver driver2 = WebRule.createWebDriver();
|
||||
|
||||
OAuthClient oauth2 = new OAuthClient(driver2);
|
||||
oauth2.doLogin("test-user@localhost", "password");
|
||||
|
||||
String sessionId2 = events.expectLogin().assertEvent().getSessionId();
|
||||
assertNotEquals(sessionId, sessionId2);
|
||||
|
||||
// Check session 1 logged-in
|
||||
oauth.openLoginForm();
|
||||
events.expectLogin().session(sessionId).detail(Details.AUTH_METHOD, "sso").removeDetail(Details.USERNAME).assertEvent();
|
||||
|
||||
// Check session 2 logged-in
|
||||
oauth2.openLoginForm();
|
||||
events.expectLogin().session(sessionId2).detail(Details.AUTH_METHOD, "sso").removeDetail(Details.USERNAME).assertEvent();
|
||||
|
||||
// Logout session 1 by redirect
|
||||
// Logout session 1 by redirect
|
||||
driver.navigate().to(oauth.getLogoutUrl(AppPage.baseUrl, null));
|
||||
events.expectLogout(sessionId).detail(Details.REDIRECT_URI, AppPage.baseUrl).assertEvent();
|
||||
|
||||
// Check session 2 logged-in
|
||||
oauth2.openLoginForm();
|
||||
events.expectLogin().session(sessionId2).detail(Details.AUTH_METHOD, "sso").removeDetail(Details.USERNAME).assertEvent();
|
||||
|
||||
// Check session 1 not logged-in
|
||||
// Check session 1 not logged-in
|
||||
oauth.openLoginForm();
|
||||
assertEquals(oauth.getLoginFormUrl(), driver.getCurrentUrl());
|
||||
|
||||
|
@ -157,19 +140,10 @@ public class LogoutTest {
|
|||
oauth.doLogin("test-user@localhost", "password");
|
||||
String sessionId3 = events.expectLogin().assertEvent().getSessionId();
|
||||
assertNotEquals(sessionId, sessionId3);
|
||||
assertNotEquals(sessionId2, sessionId3);
|
||||
|
||||
// Logout session 2 by session_state
|
||||
oauth2.doLogout(null, sessionId2);
|
||||
events.expectLogout(sessionId2).removeDetail(Details.REDIRECT_URI).assertEvent();
|
||||
|
||||
// Check session 3 logged-in
|
||||
oauth.openLoginForm();
|
||||
events.expectLogin().session(sessionId3).detail(Details.AUTH_METHOD, "sso").removeDetail(Details.USERNAME).assertEvent();
|
||||
|
||||
// Check session 2 not logged-in
|
||||
oauth2.openLoginForm();
|
||||
assertEquals(oauth2.getLoginFormUrl(), driver2.getCurrentUrl());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -305,8 +305,13 @@ public class AccessTokenTest {
|
|||
{
|
||||
builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
|
||||
URI logoutUri = TokenService.logoutUrl(builder).build("test");
|
||||
Response response = client.target(logoutUri).queryParam("session_state", tokenResponse.getSessionState()).request().get();
|
||||
Assert.assertEquals(200, response.getStatus());
|
||||
String header = BasicAuthHelper.createHeader("test-app", "password");
|
||||
Form form = new Form();
|
||||
form.param("refresh_token", tokenResponse.getRefreshToken());
|
||||
Response response = client.target(logoutUri).request()
|
||||
.header(HttpHeaders.AUTHORIZATION, header)
|
||||
.post(Entity.form(form));
|
||||
Assert.assertEquals(204, response.getStatus());
|
||||
response.close();
|
||||
}
|
||||
{
|
||||
|
|
|
@ -131,13 +131,9 @@ public class ResourceOwnerPasswordCredentialsGrantTest {
|
|||
.removeDetail(Details.REDIRECT_URI)
|
||||
.assertEvent();
|
||||
|
||||
HttpResponse logoutResponse = oauth.doLogout(null, accessToken.getSessionState());
|
||||
assertEquals(200, logoutResponse.getStatusLine().getStatusCode());
|
||||
events.expectLogout(accessToken.getSessionState()).removeDetail(Details.REDIRECT_URI).assertEvent();
|
||||
|
||||
logoutResponse = oauth.doLogout(null, accessToken.getSessionState());
|
||||
assertEquals(200, logoutResponse.getStatusLine().getStatusCode());
|
||||
events.expectLogout(accessToken.getSessionState()).user((String) null).removeDetail(Details.REDIRECT_URI).error(Errors.USER_SESSION_NOT_FOUND).assertEvent();
|
||||
HttpResponse logoutResponse = oauth.doLogout(response.getRefreshToken(), "secret");
|
||||
assertEquals(204, logoutResponse.getStatusLine().getStatusCode());
|
||||
events.expectLogout(accessToken.getSessionState()).client("resource-owner").removeDetail(Details.REDIRECT_URI).assertEvent();
|
||||
|
||||
response = oauth.doRefreshTokenRequest(response.getRefreshToken(), "secret");
|
||||
assertEquals(400, response.getStatusCode());
|
||||
|
|
Loading…
Reference in a new issue