KEYCLOAK-1150

'iss' should be URL not just realm name
This commit is contained in:
Stian Thorgersen 2015-03-26 12:55:53 +01:00
parent d36ee0d0af
commit b727087f04
36 changed files with 1041 additions and 978 deletions

View file

@ -50,7 +50,7 @@ public class KeycloakSecurityContext implements Serializable {
public String getRealm() { public String getRealm() {
// Assumption that issuer contains realm name // Assumption that issuer contains realm name
return token.getIssuer(); return token.getIssuer().substring(token.getIssuer().lastIndexOf('/') + 1);
} }
// SERIALIZATION // SERIALIZATION

View file

@ -12,11 +12,11 @@ import java.security.PublicKey;
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class RSATokenVerifier { public class RSATokenVerifier {
public static AccessToken verifyToken(String tokenString, PublicKey realmKey, String realm) throws VerificationException { public static AccessToken verifyToken(String tokenString, PublicKey realmKey, String realmUrl) throws VerificationException {
return verifyToken(tokenString, realmKey, realm, true); return verifyToken(tokenString, realmKey, realmUrl, true);
} }
public static AccessToken verifyToken(String tokenString, PublicKey realmKey, String realm, boolean checkActive) throws VerificationException { public static AccessToken verifyToken(String tokenString, PublicKey realmKey, String realmUrl, boolean checkActive) throws VerificationException {
JWSInput input = null; JWSInput input = null;
try { try {
input = new JWSInput(tokenString); input = new JWSInput(tokenString);
@ -35,7 +35,7 @@ public class RSATokenVerifier {
if (user == null) { if (user == null) {
throw new VerificationException("Token user was null."); throw new VerificationException("Token user was null.");
} }
if (!realm.equals(token.getIssuer())) { if (!realmUrl.equals(token.getIssuer())) {
throw new VerificationException("Token audience doesn't match domain."); throw new VerificationException("Token audience doesn't match domain.");
} }

View file

@ -72,7 +72,7 @@ public class RSAVerifierTest {
token = new AccessToken(); token = new AccessToken();
token.subject("CN=Client") token.subject("CN=Client")
.issuer("domain") .issuer("http://localhost:8080/auth/realm")
.addAccess("service").addRole("admin"); .addAccess("service").addRole("admin");
} }
@ -102,7 +102,7 @@ public class RSAVerifierTest {
} }
private AccessToken verifySkeletonKeyToken(String encoded) throws VerificationException { private AccessToken verifySkeletonKeyToken(String encoded) throws VerificationException {
return RSATokenVerifier.verifyToken(encoded, idpPair.getPublic(), "domain"); return RSATokenVerifier.verifyToken(encoded, idpPair.getPublic(), "http://localhost:8080/auth/realm");
} }
/* /*

View file

@ -104,7 +104,7 @@ public class SkeletonKeyTokenTest {
private AccessToken createSimpleToken() { private AccessToken createSimpleToken() {
AccessToken token = new AccessToken(); AccessToken token = new AccessToken();
token.id("111"); token.id("111");
token.issuer("acme"); token.issuer("http://localhost:8080/auth/acme");
token.addAccess("foo").addRole("admin"); token.addAccess("foo").addRole("admin");
token.addAccess("bar").addRole("user"); token.addAccess("bar").addRole("user");
return token; return token;

View file

@ -79,6 +79,30 @@
<section> <section>
<title>Version specific migration</title> <title>Version specific migration</title>
<section>
<title>Migrating from 1.1.0.Final to 1.2.0.Beta1</title>
<simplesect>
<title><literal>iss</literal> in access and id tokens</title>
<para>
The value of <literal>iss</literal> claim in access and id tokens have changed from <literal>realm name</literal>
to <literal>realm url</literal>. This is required by OpenID Connect specification. If you're using our adapters
there's no change required, other than if you've been using bearer-only without specifying <literal>auth-server-url</literal>
you have to add it now. If you're using another library (or RSATokenVerifier) you need to make the corresponding
changes when verifying <literal>iss</literal>.
</para>
</simplesect>
<simplesect>
<title>OpenID Connect endpoints</title>
<para>
To comply with OpenID Connect specification the authentication and token endpoints have been changed
to having a single authentication endpoint and a single token endpoint. As per-spec <literal>response_type</literal>
and <literal>grant_type</literal> parameters are used to select the required flow. The old endpoints (<literal>/realms/{realm}/protocols/openid-connect/login</literal>,
<literal>/realms/{realm}/protocols/openid-connect/grants/access</literal>, <literal>/realms/{realm}/protocols/openid-connect/refresh</literal>,
<literal>/realms/{realm}/protocols/openid-connect/access/codes)</literal> are now deprecated and will be removed
in a future version.
</para>
</simplesect>
</section>
<section> <section>
<title>Migrating from 1.1.0.Beta2 to 1.1.0.Final</title> <title>Migrating from 1.1.0.Beta2 to 1.1.0.Final</title>
<itemizedlist> <itemizedlist>

View file

@ -2,6 +2,7 @@
"realm" : "demo", "realm" : "demo",
"resource" : "database-service", "resource" : "database-service",
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB", "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-server-url": "/auth",
"bearer-only" : true, "bearer-only" : true,
"ssl-required" : "external" "ssl-required" : "external"
} }

View file

@ -52,7 +52,7 @@ public class ProtectedServlet extends HttpServlet {
PrintWriter writer = resp.getWriter(); PrintWriter writer = resp.getWriter();
writer.write("Realm: "); writer.write("Realm: ");
writer.write(principal.getKeycloakSecurityContext().getIdToken().getIssuer()); writer.write(principal.getKeycloakSecurityContext().getRealm());
writer.write("<br/>User: "); writer.write("<br/>User: ");
writer.write(principal.getKeycloakSecurityContext().getIdToken().getPreferredUsername()); writer.write(principal.getKeycloakSecurityContext().getIdToken().getPreferredUsername());

View file

@ -64,7 +64,7 @@ public class BearerTokenRequestAuthenticator {
protected AuthOutcome authenticateToken(HttpFacade exchange, String tokenString) { protected AuthOutcome authenticateToken(HttpFacade exchange, String tokenString) {
try { try {
token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealm()); token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealmInfoUrl());
} catch (VerificationException e) { } catch (VerificationException e) {
log.error("Failed to verify token", e); log.error("Failed to verify token", e);
challenge = challengeResponse(exchange, "invalid_token", e.getMessage()); challenge = challengeResponse(exchange, "invalid_token", e.getMessage());

View file

@ -54,7 +54,7 @@ public class CookieTokenStore {
try { try {
// Skip check if token is active now. It's supposed to be done later by the caller // Skip check if token is active now. It's supposed to be done later by the caller
AccessToken accessToken = RSATokenVerifier.verifyToken(accessTokenString, deployment.getRealmKey(), deployment.getRealm(), false); AccessToken accessToken = RSATokenVerifier.verifyToken(accessTokenString, deployment.getRealmKey(), deployment.getRealmInfoUrl(), false);
IDToken idToken; IDToken idToken;
if (idTokenString != null && idTokenString.length() > 0) { if (idTokenString != null && idTokenString.length() > 0) {
JWSInput input = new JWSInput(idTokenString); JWSInput input = new JWSInput(idTokenString);

View file

@ -311,7 +311,7 @@ public class OAuthRequestAuthenticator {
refreshToken = tokenResponse.getRefreshToken(); refreshToken = tokenResponse.getRefreshToken();
idTokenString = tokenResponse.getIdToken(); idTokenString = tokenResponse.getIdToken();
try { try {
token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealm()); token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealmInfoUrl());
if (idTokenString != null) { if (idTokenString != null) {
JWSInput input = new JWSInput(idTokenString); JWSInput input = new JWSInput(idTokenString);
try { try {

View file

@ -107,7 +107,7 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext
String tokenString = response.getToken(); String tokenString = response.getToken();
AccessToken token = null; AccessToken token = null;
try { try {
token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealm()); token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealmInfoUrl());
log.debug("Token Verification succeeded!"); log.debug("Token Verification succeeded!");
} catch (VerificationException e) { } catch (VerificationException e) {
log.error("failed verification of token"); log.error("failed verification of token");

View file

@ -173,7 +173,7 @@ public abstract class AbstractKeycloakLoginModule implements LoginModule {
protected Auth bearerAuth(String tokenString) throws VerificationException { protected Auth bearerAuth(String tokenString) throws VerificationException {
AccessToken token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealm()); AccessToken token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealmInfoUrl());
boolean verifyCaller; boolean verifyCaller;
if (deployment.isUseResourceRoleMappings()) { if (deployment.isUseResourceRoleMappings()) {

View file

@ -193,7 +193,7 @@ public class KeycloakInstalled {
refreshToken = tokenResponse.getRefreshToken(); refreshToken = tokenResponse.getRefreshToken();
idTokenString = tokenResponse.getIdToken(); idTokenString = tokenResponse.getIdToken();
token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealm()); token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealmInfoUrl());
if (idTokenString != null) { if (idTokenString != null) {
JWSInput input = new JWSInput(idTokenString); JWSInput input = new JWSInput(idTokenString);
try { try {

View file

@ -59,6 +59,7 @@ public class OIDCLoginProtocol implements LoginProtocol {
public static final String PROMPT_PARAM = "prompt"; public static final String PROMPT_PARAM = "prompt";
public static final String LOGIN_HINT_PARAM = "login_hint"; public static final String LOGIN_HINT_PARAM = "login_hint";
public static final String LOGOUT_REDIRECT_URI = "OIDC_LOGOUT_REDIRECT_URI"; public static final String LOGOUT_REDIRECT_URI = "OIDC_LOGOUT_REDIRECT_URI";
public static final String ISSUER = "iss";
private static final Logger log = Logger.getLogger(OIDCLoginProtocol.class); private static final Logger log = Logger.getLogger(OIDCLoginProtocol.class);

View file

@ -314,7 +314,7 @@ public class TokenManager {
token.audience(client.getClientId()); token.audience(client.getClientId());
token.issuedNow(); token.issuedNow();
token.issuedFor(client.getClientId()); token.issuedFor(client.getClientId());
token.issuer(realm.getName()); token.issuer(clientSession.getNote(OIDCLoginProtocol.ISSUER));
if (session != null) { if (session != null) {
token.setSessionState(session.getId()); token.setSessionState(session.getId());
} }

View file

@ -223,6 +223,7 @@ public class AuthorizationEndpoint {
clientSession.setNote(ClientSessionCode.ACTION_KEY, KeycloakModelUtils.generateCodeSecret()); clientSession.setNote(ClientSessionCode.ACTION_KEY, KeycloakModelUtils.generateCodeSecret());
clientSession.setNote(OIDCLoginProtocol.RESPONSE_TYPE_PARAM, responseType); clientSession.setNote(OIDCLoginProtocol.RESPONSE_TYPE_PARAM, responseType);
clientSession.setNote(OIDCLoginProtocol.REDIRECT_URI_PARAM, redirectUriParam); clientSession.setNote(OIDCLoginProtocol.REDIRECT_URI_PARAM, redirectUriParam);
clientSession.setNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()));
if (state != null) clientSession.setNote(OIDCLoginProtocol.STATE_PARAM, state); if (state != null) clientSession.setNote(OIDCLoginProtocol.STATE_PARAM, state);
if (scope != null) clientSession.setNote(OIDCLoginProtocol.SCOPE_PARAM, scope); if (scope != null) clientSession.setNote(OIDCLoginProtocol.SCOPE_PARAM, scope);

View file

@ -29,6 +29,7 @@ import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.ClientSessionCode; import org.keycloak.services.managers.ClientSessionCode;
import org.keycloak.services.resources.Cors; import org.keycloak.services.resources.Cors;
import org.keycloak.services.resources.flows.Urls;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.OPTIONS; import javax.ws.rs.OPTIONS;
@ -319,6 +320,7 @@ public class TokenEndpoint {
ClientSessionModel clientSession = sessions.createClientSession(realm, client); ClientSessionModel clientSession = sessions.createClientSession(realm, client);
clientSession.setAuthMethod(OIDCLoginProtocol.LOGIN_PROTOCOL); clientSession.setAuthMethod(OIDCLoginProtocol.LOGIN_PROTOCOL);
clientSession.setNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()));
TokenManager.attachClientSession(userSession, clientSession); TokenManager.attachClientSession(userSession, clientSession);

View file

@ -39,6 +39,7 @@ import org.keycloak.services.managers.AppAuthManager;
import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.EventsManager; import org.keycloak.services.managers.EventsManager;
import org.keycloak.services.resources.Cors; import org.keycloak.services.resources.Cors;
import org.keycloak.services.resources.flows.Urls;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam; import javax.ws.rs.FormParam;
@ -52,6 +53,7 @@ import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -66,6 +68,9 @@ public class UserInfoEndpoint {
@Context @Context
private HttpResponse response; private HttpResponse response;
@Context
private UriInfo uriInfo;
@Context @Context
private KeycloakSession session; private KeycloakSession session;
@ -114,7 +119,7 @@ public class UserInfoEndpoint {
AccessToken token = null; AccessToken token = null;
try { try {
token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), realm.getName()); token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()));
} catch (Exception e) { } catch (Exception e) {
throw new ErrorResponseException(OAuthErrorException.INVALID_GRANT, "Token invalid", Status.FORBIDDEN); throw new ErrorResponseException(OAuthErrorException.INVALID_GRANT, "Token invalid", Status.FORBIDDEN);
} }

View file

@ -15,6 +15,7 @@ import org.keycloak.models.RealmModel;
import org.keycloak.protocol.oidc.TokenManager; import org.keycloak.protocol.oidc.TokenManager;
import org.keycloak.representations.AccessToken; import org.keycloak.representations.AccessToken;
import org.keycloak.services.ErrorResponseException; import org.keycloak.services.ErrorResponseException;
import org.keycloak.services.resources.flows.Urls;
import javax.ws.rs.GET; import javax.ws.rs.GET;
import javax.ws.rs.Path; import javax.ws.rs.Path;
@ -68,7 +69,7 @@ public class ValidateTokenEndpoint {
event.event(EventType.VALIDATE_ACCESS_TOKEN); event.event(EventType.VALIDATE_ACCESS_TOKEN);
AccessToken token = null; AccessToken token = null;
try { try {
token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), realm.getName()); token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()));
} catch (Exception e) { } catch (Exception e) {
Map<String, String> err = new HashMap<String, String>(); Map<String, String> err = new HashMap<String, String>();
err.put(OAuth2Constants.ERROR, OAuthErrorException.INVALID_GRANT); err.put(OAuth2Constants.ERROR, OAuthErrorException.INVALID_GRANT);

View file

@ -32,6 +32,7 @@ import org.keycloak.services.resources.IdentityBrokerService;
import org.keycloak.services.resources.LoginActionsService; import org.keycloak.services.resources.LoginActionsService;
import org.keycloak.services.resources.RealmsResource; import org.keycloak.services.resources.RealmsResource;
import org.keycloak.services.resources.flows.Flows; import org.keycloak.services.resources.flows.Flows;
import org.keycloak.services.resources.flows.Urls;
import org.keycloak.services.util.CookieHelper; import org.keycloak.services.util.CookieHelper;
import org.keycloak.services.validation.Validation; import org.keycloak.services.validation.Validation;
import org.keycloak.util.Time; import org.keycloak.util.Time;
@ -192,12 +193,12 @@ public class AuthenticationManager {
} }
public static AccessToken createIdentityToken(RealmModel realm, UserModel user, UserSessionModel session) { public static AccessToken createIdentityToken(RealmModel realm, UserModel user, UserSessionModel session, String issuer) {
AccessToken token = new AccessToken(); AccessToken token = new AccessToken();
token.id(KeycloakModelUtils.generateId()); token.id(KeycloakModelUtils.generateId());
token.issuedNow(); token.issuedNow();
token.subject(user.getId()); token.subject(user.getId());
token.issuer(realm.getName()); token.issuer(issuer);
if (session != null) { if (session != null) {
token.setSessionState(session.getId()); token.setSessionState(session.getId());
} }
@ -209,7 +210,8 @@ public class AuthenticationManager {
public static void createLoginCookie(RealmModel realm, UserModel user, UserSessionModel session, UriInfo uriInfo, ClientConnection connection) { public static void createLoginCookie(RealmModel realm, UserModel user, UserSessionModel session, UriInfo uriInfo, ClientConnection connection) {
String cookiePath = getIdentityCookiePath(realm, uriInfo); String cookiePath = getIdentityCookiePath(realm, uriInfo);
AccessToken identityToken = createIdentityToken(realm, user, session); String issuer = Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName());
AccessToken identityToken = createIdentityToken(realm, user, session, issuer);
String encoded = encodeToken(realm, identityToken); String encoded = encodeToken(realm, identityToken);
boolean secureOnly = realm.getSslRequired().isRequired(connection); boolean secureOnly = realm.getSslRequired().isRequired(connection);
int maxAge = NewCookie.DEFAULT_MAX_AGE; int maxAge = NewCookie.DEFAULT_MAX_AGE;
@ -443,7 +445,7 @@ public class AuthenticationManager {
protected AuthResult verifyIdentityToken(KeycloakSession session, RealmModel realm, UriInfo uriInfo, ClientConnection connection, boolean checkActive, String tokenString, HttpHeaders headers) { protected AuthResult verifyIdentityToken(KeycloakSession session, RealmModel realm, UriInfo uriInfo, ClientConnection connection, boolean checkActive, String tokenString, HttpHeaders headers) {
try { try {
AccessToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), realm.getName(), checkActive); AccessToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()), checkActive);
if (checkActive) { if (checkActive) {
if (!token.isActive() || token.getIssuedAt() < realm.getNotBefore()) { if (!token.isActive() || token.getIssuedAt() < realm.getNotBefore()) {
logger.debug("identity cookie expired"); logger.debug("identity cookie expired");

View file

@ -140,7 +140,7 @@ public class AdminRoot {
} catch (IOException e) { } catch (IOException e) {
throw new UnauthorizedException("Bearer token format error"); throw new UnauthorizedException("Bearer token format error");
} }
String realmName = token.getIssuer(); String realmName = token.getIssuer().substring(token.getIssuer().lastIndexOf('/') + 1);
RealmManager realmManager = new RealmManager(session); RealmManager realmManager = new RealmManager(session);
RealmModel realm = realmManager.getRealmByName(realmName); RealmModel realm = realmManager.getRealmByName(realmName);
if (realm == null) { if (realm == null) {

View file

@ -158,6 +158,10 @@ public class Urls {
return requiredActionsBase(baseUri).path(LoginActionsService.class, "usernameReminder"); return requiredActionsBase(baseUri).path(LoginActionsService.class, "usernameReminder");
} }
public static String realmIssuer(URI baseUri, String realmId) {
return realmBase(baseUri).path("{realm}").build(realmId).toString();
}
private static UriBuilder realmBase(URI baseUri) { private static UriBuilder realmBase(URI baseUri) {
return UriBuilder.fromUri(baseUri).path(RealmsResource.class); return UriBuilder.fromUri(baseUri).path(RealmsResource.class);
} }

View file

@ -225,7 +225,7 @@ public class OAuthClient {
public AccessToken verifyToken(String token) { public AccessToken verifyToken(String token) {
try { try {
return RSATokenVerifier.verifyToken(token, realmPublicKey, realm); return RSATokenVerifier.verifyToken(token, realmPublicKey, baseUrl + "/realms/" + realm);
} catch (VerificationException e) { } catch (VerificationException e) {
throw new RuntimeException("Failed to verify token", e); throw new RuntimeException("Failed to verify token", e);
} }

View file

@ -1,471 +1,471 @@
/* /*
* JBoss, Home of Professional Open Source. * JBoss, Home of Professional Open Source.
* Copyright 2012, Red Hat, Inc., and individual contributors * Copyright 2012, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the * as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors. * distribution for a full listing of individual contributors.
* *
* This is free software; you can redistribute it and/or modify it * This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as * under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of * published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version. * the License, or (at your option) any later version.
* *
* This software is distributed in the hope that it will be useful, * This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free * License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org. * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/ */
package org.keycloak.testsuite.account; package org.keycloak.testsuite.account;
import org.junit.After; import org.junit.After;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.ClassRule; import org.junit.ClassRule;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.keycloak.events.Details; import org.keycloak.events.Details;
import org.keycloak.events.Event; import org.keycloak.events.Event;
import org.keycloak.events.EventType; import org.keycloak.events.EventType;
import org.keycloak.models.ApplicationModel; import org.keycloak.models.ApplicationModel;
import org.keycloak.models.PasswordPolicy; import org.keycloak.models.PasswordPolicy;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.UserCredentialModel; import org.keycloak.models.UserCredentialModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.utils.TimeBasedOTP; import org.keycloak.models.utils.TimeBasedOTP;
import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.resources.AccountService; import org.keycloak.services.resources.AccountService;
import org.keycloak.services.resources.RealmsResource; import org.keycloak.services.resources.RealmsResource;
import org.keycloak.testsuite.AssertEvents; import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.OAuthClient; import org.keycloak.testsuite.OAuthClient;
import org.keycloak.testsuite.pages.AccountLogPage; import org.keycloak.testsuite.pages.AccountLogPage;
import org.keycloak.testsuite.pages.AccountPasswordPage; import org.keycloak.testsuite.pages.AccountPasswordPage;
import org.keycloak.testsuite.pages.AccountSessionsPage; import org.keycloak.testsuite.pages.AccountSessionsPage;
import org.keycloak.testsuite.pages.AccountTotpPage; import org.keycloak.testsuite.pages.AccountTotpPage;
import org.keycloak.testsuite.pages.AccountUpdateProfilePage; import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
import org.keycloak.testsuite.pages.AppPage; import org.keycloak.testsuite.pages.AppPage;
import org.keycloak.testsuite.pages.AppPage.RequestType; import org.keycloak.testsuite.pages.AppPage.RequestType;
import org.keycloak.testsuite.pages.ErrorPage; import org.keycloak.testsuite.pages.ErrorPage;
import org.keycloak.testsuite.pages.LoginPage; import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.pages.RegisterPage; import org.keycloak.testsuite.pages.RegisterPage;
import org.keycloak.testsuite.rule.KeycloakRule; import org.keycloak.testsuite.rule.KeycloakRule;
import org.keycloak.testsuite.rule.KeycloakRule.KeycloakSetup; import org.keycloak.testsuite.rule.KeycloakRule.KeycloakSetup;
import org.keycloak.testsuite.rule.WebResource; import org.keycloak.testsuite.rule.WebResource;
import org.keycloak.testsuite.rule.WebRule; import org.keycloak.testsuite.rule.WebRule;
import org.openqa.selenium.By; import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebDriver;
import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriBuilder;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
/** /**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/ */
public class AccountTest { public class AccountTest {
@ClassRule @ClassRule
public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakSetup() { public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakSetup() {
@Override @Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
UserModel user = manager.getSession().users().getUserByUsername("test-user@localhost", appRealm); UserModel user = manager.getSession().users().getUserByUsername("test-user@localhost", appRealm);
ApplicationModel accountApp = appRealm.getApplicationNameMap().get(org.keycloak.models.Constants.ACCOUNT_MANAGEMENT_APP); ApplicationModel accountApp = appRealm.getApplicationNameMap().get(org.keycloak.models.Constants.ACCOUNT_MANAGEMENT_APP);
UserModel user2 = manager.getSession().users().addUser(appRealm, "test-user-no-access@localhost"); UserModel user2 = manager.getSession().users().addUser(appRealm, "test-user-no-access@localhost");
user2.setEnabled(true); user2.setEnabled(true);
for (String r : accountApp.getDefaultRoles()) { for (String r : accountApp.getDefaultRoles()) {
user2.deleteRoleMapping(accountApp.getRole(r)); user2.deleteRoleMapping(accountApp.getRole(r));
} }
UserCredentialModel creds = new UserCredentialModel(); UserCredentialModel creds = new UserCredentialModel();
creds.setType(CredentialRepresentation.PASSWORD); creds.setType(CredentialRepresentation.PASSWORD);
creds.setValue("password"); creds.setValue("password");
user2.updateCredential(creds); user2.updateCredential(creds);
} }
}); });
private static final UriBuilder BASE = UriBuilder.fromUri("http://localhost:8081/auth"); private static final UriBuilder BASE = UriBuilder.fromUri("http://localhost:8081/auth");
private static final String ACCOUNT_URL = RealmsResource.accountUrl(BASE.clone()).build("test").toString(); private static final String ACCOUNT_URL = RealmsResource.accountUrl(BASE.clone()).build("test").toString();
public static String ACCOUNT_REDIRECT = AccountService.loginRedirectUrl(BASE.clone()).build("test").toString(); public static String ACCOUNT_REDIRECT = AccountService.loginRedirectUrl(BASE.clone()).build("test").toString();
@Rule @Rule
public AssertEvents events = new AssertEvents(keycloakRule); public AssertEvents events = new AssertEvents(keycloakRule);
@Rule @Rule
public WebRule webRule = new WebRule(this); public WebRule webRule = new WebRule(this);
@WebResource @WebResource
protected WebDriver driver; protected WebDriver driver;
@WebResource @WebResource
protected OAuthClient oauth; protected OAuthClient oauth;
@WebResource @WebResource
protected AppPage appPage; protected AppPage appPage;
@WebResource @WebResource
protected LoginPage loginPage; protected LoginPage loginPage;
@WebResource @WebResource
protected RegisterPage registerPage; protected RegisterPage registerPage;
@WebResource @WebResource
protected AccountPasswordPage changePasswordPage; protected AccountPasswordPage changePasswordPage;
@WebResource @WebResource
protected AccountUpdateProfilePage profilePage; protected AccountUpdateProfilePage profilePage;
@WebResource @WebResource
protected AccountTotpPage totpPage; protected AccountTotpPage totpPage;
@WebResource @WebResource
protected AccountLogPage logPage; protected AccountLogPage logPage;
@WebResource @WebResource
protected AccountSessionsPage sessionsPage; protected AccountSessionsPage sessionsPage;
@WebResource @WebResource
protected ErrorPage errorPage; protected ErrorPage errorPage;
private TimeBasedOTP totp = new TimeBasedOTP(); private TimeBasedOTP totp = new TimeBasedOTP();
private String userId; private String userId;
@Before @Before
public void before() { public void before() {
oauth.state("mystate"); // keycloak enforces that a state param has been sent by client oauth.state("mystate"); // keycloak enforces that a state param has been sent by client
userId = keycloakRule.getUser("test", "test-user@localhost").getId(); userId = keycloakRule.getUser("test", "test-user@localhost").getId();
} }
@After @After
public void after() { public void after() {
keycloakRule.update(new KeycloakSetup() { keycloakRule.update(new KeycloakSetup() {
@Override @Override
public void config(RealmManager manager, RealmModel defaultRealm, RealmModel appRealm) { public void config(RealmManager manager, RealmModel defaultRealm, RealmModel appRealm) {
UserModel user = manager.getSession().users().getUserByUsername("test-user@localhost", appRealm); UserModel user = manager.getSession().users().getUserByUsername("test-user@localhost", appRealm);
UserCredentialModel cred = new UserCredentialModel(); UserCredentialModel cred = new UserCredentialModel();
cred.setType(CredentialRepresentation.PASSWORD); cred.setType(CredentialRepresentation.PASSWORD);
cred.setValue("password"); cred.setValue("password");
user.updateCredential(cred); user.updateCredential(cred);
} }
}); });
} }
//@Test @Ignore //@Test @Ignore
public void runit() throws Exception { public void runit() throws Exception {
Thread.sleep(10000000); Thread.sleep(10000000);
} }
@Test @Test
public void returnToAppFromQueryParam() { public void returnToAppFromQueryParam() {
driver.navigate().to(AccountUpdateProfilePage.PATH + "?referrer=test-app"); driver.navigate().to(AccountUpdateProfilePage.PATH + "?referrer=test-app");
loginPage.login("test-user@localhost", "password"); loginPage.login("test-user@localhost", "password");
Assert.assertTrue(profilePage.isCurrent()); Assert.assertTrue(profilePage.isCurrent());
profilePage.backToApplication(); profilePage.backToApplication();
Assert.assertTrue(appPage.isCurrent()); Assert.assertTrue(appPage.isCurrent());
driver.navigate().to(AccountUpdateProfilePage.PATH + "?referrer=test-app&referrer_uri=http://localhost:8081/app?test"); driver.navigate().to(AccountUpdateProfilePage.PATH + "?referrer=test-app&referrer_uri=http://localhost:8081/app?test");
Assert.assertTrue(profilePage.isCurrent()); Assert.assertTrue(profilePage.isCurrent());
profilePage.backToApplication(); profilePage.backToApplication();
Assert.assertTrue(appPage.isCurrent()); Assert.assertTrue(appPage.isCurrent());
Assert.assertEquals(appPage.baseUrl + "?test", driver.getCurrentUrl()); Assert.assertEquals(appPage.baseUrl + "?test", driver.getCurrentUrl());
driver.navigate().to(AccountUpdateProfilePage.PATH + "?referrer=test-app"); driver.navigate().to(AccountUpdateProfilePage.PATH + "?referrer=test-app");
Assert.assertTrue(profilePage.isCurrent()); Assert.assertTrue(profilePage.isCurrent());
driver.findElement(By.linkText("Authenticator")).click(); driver.findElement(By.linkText("Authenticator")).click();
Assert.assertTrue(totpPage.isCurrent()); Assert.assertTrue(totpPage.isCurrent());
driver.findElement(By.linkText("Account")).click(); driver.findElement(By.linkText("Account")).click();
Assert.assertTrue(profilePage.isCurrent()); Assert.assertTrue(profilePage.isCurrent());
profilePage.backToApplication(); profilePage.backToApplication();
Assert.assertTrue(appPage.isCurrent()); Assert.assertTrue(appPage.isCurrent());
events.clear(); events.clear();
} }
@Test @Test
public void changePassword() { public void changePassword() {
changePasswordPage.open(); changePasswordPage.open();
loginPage.login("test-user@localhost", "password"); loginPage.login("test-user@localhost", "password");
String sessionId = events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent().getSessionId(); String sessionId = events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent().getSessionId();
changePasswordPage.changePassword("", "new-password", "new-password"); changePasswordPage.changePassword("", "new-password", "new-password");
Assert.assertEquals("Please specify password.", profilePage.getError()); Assert.assertEquals("Please specify password.", profilePage.getError());
changePasswordPage.changePassword("password", "new-password", "new-password2"); changePasswordPage.changePassword("password", "new-password", "new-password2");
Assert.assertEquals("Password confirmation doesn't match.", profilePage.getError()); Assert.assertEquals("Password confirmation doesn't match.", profilePage.getError());
changePasswordPage.changePassword("password", "new-password", "new-password"); changePasswordPage.changePassword("password", "new-password", "new-password");
Assert.assertEquals("Your password has been updated.", profilePage.getSuccess()); Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent(); events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
changePasswordPage.logout(); changePasswordPage.logout();
events.expectLogout(sessionId).detail(Details.REDIRECT_URI, changePasswordPage.getPath()).assertEvent(); events.expectLogout(sessionId).detail(Details.REDIRECT_URI, changePasswordPage.getPath()).assertEvent();
loginPage.open(); loginPage.open();
loginPage.login("test-user@localhost", "password"); loginPage.login("test-user@localhost", "password");
Assert.assertEquals("Invalid username or password.", loginPage.getError()); Assert.assertEquals("Invalid username or password.", loginPage.getError());
events.expectLogin().session((String) null).error("invalid_user_credentials").assertEvent(); events.expectLogin().session((String) null).error("invalid_user_credentials").assertEvent();
loginPage.open(); loginPage.open();
loginPage.login("test-user@localhost", "new-password"); loginPage.login("test-user@localhost", "new-password");
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType()); Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
events.expectLogin().assertEvent(); events.expectLogin().assertEvent();
} }
@Test @Test
public void changePasswordWithPasswordPolicy() { public void changePasswordWithPasswordPolicy() {
keycloakRule.update(new KeycloakRule.KeycloakSetup() { keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override @Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
appRealm.setPasswordPolicy(new PasswordPolicy("length")); appRealm.setPasswordPolicy(new PasswordPolicy("length"));
} }
}); });
try { try {
changePasswordPage.open(); changePasswordPage.open();
loginPage.login("test-user@localhost", "password"); loginPage.login("test-user@localhost", "password");
events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent(); events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=password").assertEvent();
changePasswordPage.changePassword("", "new", "new"); changePasswordPage.changePassword("", "new", "new");
Assert.assertEquals("Please specify password.", profilePage.getError()); Assert.assertEquals("Please specify password.", profilePage.getError());
changePasswordPage.changePassword("password", "new-password", "new-password"); changePasswordPage.changePassword("password", "new-password", "new-password");
Assert.assertEquals("Your password has been updated.", profilePage.getSuccess()); Assert.assertEquals("Your password has been updated.", profilePage.getSuccess());
events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent(); events.expectAccount(EventType.UPDATE_PASSWORD).assertEvent();
} finally { } finally {
keycloakRule.update(new KeycloakRule.KeycloakSetup() { keycloakRule.update(new KeycloakRule.KeycloakSetup() {
@Override @Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
appRealm.setPasswordPolicy(new PasswordPolicy(null)); appRealm.setPasswordPolicy(new PasswordPolicy(null));
} }
}); });
} }
} }
@Test @Test
public void changeProfile() { public void changeProfile() {
profilePage.open(); profilePage.open();
loginPage.login("test-user@localhost", "password"); loginPage.login("test-user@localhost", "password");
events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT).assertEvent(); events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT).assertEvent();
Assert.assertEquals("Tom", profilePage.getFirstName()); Assert.assertEquals("Tom", profilePage.getFirstName());
Assert.assertEquals("Brady", profilePage.getLastName()); Assert.assertEquals("Brady", profilePage.getLastName());
Assert.assertEquals("test-user@localhost", profilePage.getEmail()); Assert.assertEquals("test-user@localhost", profilePage.getEmail());
// All fields are required, so there should be an error when something is missing. // All fields are required, so there should be an error when something is missing.
profilePage.updateProfile("", "New last", "new@email.com"); profilePage.updateProfile("", "New last", "new@email.com");
Assert.assertEquals("Please specify first name.", profilePage.getError()); Assert.assertEquals("Please specify first name.", profilePage.getError());
Assert.assertEquals("", profilePage.getFirstName()); Assert.assertEquals("", profilePage.getFirstName());
Assert.assertEquals("New last", profilePage.getLastName()); Assert.assertEquals("New last", profilePage.getLastName());
Assert.assertEquals("new@email.com", profilePage.getEmail()); Assert.assertEquals("new@email.com", profilePage.getEmail());
events.assertEmpty(); events.assertEmpty();
profilePage.updateProfile("New first", "", "new@email.com"); profilePage.updateProfile("New first", "", "new@email.com");
Assert.assertEquals("Please specify last name.", profilePage.getError()); Assert.assertEquals("Please specify last name.", profilePage.getError());
Assert.assertEquals("New first", profilePage.getFirstName()); Assert.assertEquals("New first", profilePage.getFirstName());
Assert.assertEquals("", profilePage.getLastName()); Assert.assertEquals("", profilePage.getLastName());
Assert.assertEquals("new@email.com", profilePage.getEmail()); Assert.assertEquals("new@email.com", profilePage.getEmail());
events.assertEmpty(); events.assertEmpty();
profilePage.updateProfile("New first", "New last", ""); profilePage.updateProfile("New first", "New last", "");
Assert.assertEquals("Please specify email.", profilePage.getError()); Assert.assertEquals("Please specify email.", profilePage.getError());
Assert.assertEquals("New first", profilePage.getFirstName()); Assert.assertEquals("New first", profilePage.getFirstName());
Assert.assertEquals("New last", profilePage.getLastName()); Assert.assertEquals("New last", profilePage.getLastName());
Assert.assertEquals("", profilePage.getEmail()); Assert.assertEquals("", profilePage.getEmail());
events.assertEmpty(); events.assertEmpty();
profilePage.clickCancel(); profilePage.clickCancel();
Assert.assertEquals("Tom", profilePage.getFirstName()); Assert.assertEquals("Tom", profilePage.getFirstName());
Assert.assertEquals("Brady", profilePage.getLastName()); Assert.assertEquals("Brady", profilePage.getLastName());
Assert.assertEquals("test-user@localhost", profilePage.getEmail()); Assert.assertEquals("test-user@localhost", profilePage.getEmail());
events.assertEmpty(); events.assertEmpty();
profilePage.updateProfile("New first", "New last", "new@email.com"); profilePage.updateProfile("New first", "New last", "new@email.com");
Assert.assertEquals("Your account has been updated.", profilePage.getSuccess()); Assert.assertEquals("Your account has been updated.", profilePage.getSuccess());
Assert.assertEquals("New first", profilePage.getFirstName()); Assert.assertEquals("New first", profilePage.getFirstName());
Assert.assertEquals("New last", profilePage.getLastName()); Assert.assertEquals("New last", profilePage.getLastName());
Assert.assertEquals("new@email.com", profilePage.getEmail()); Assert.assertEquals("new@email.com", profilePage.getEmail());
events.expectAccount(EventType.UPDATE_PROFILE).assertEvent(); events.expectAccount(EventType.UPDATE_PROFILE).assertEvent();
events.expectAccount(EventType.UPDATE_EMAIL).detail(Details.PREVIOUS_EMAIL, "test-user@localhost").detail(Details.UPDATED_EMAIL, "new@email.com").assertEvent(); events.expectAccount(EventType.UPDATE_EMAIL).detail(Details.PREVIOUS_EMAIL, "test-user@localhost").detail(Details.UPDATED_EMAIL, "new@email.com").assertEvent();
} }
@Test @Test
public void setupTotp() { public void setupTotp() {
totpPage.open(); totpPage.open();
loginPage.login("test-user@localhost", "password"); loginPage.login("test-user@localhost", "password");
events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=totp").assertEvent(); events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT + "?path=totp").assertEvent();
Assert.assertTrue(totpPage.isCurrent()); Assert.assertTrue(totpPage.isCurrent());
Assert.assertFalse(driver.getPageSource().contains("Remove Google")); Assert.assertFalse(driver.getPageSource().contains("Remove Google"));
// Error with false code // Error with false code
totpPage.configure(totp.generate(totpPage.getTotpSecret() + "123")); totpPage.configure(totp.generate(totpPage.getTotpSecret() + "123"));
Assert.assertEquals("Invalid authenticator code.", profilePage.getError()); Assert.assertEquals("Invalid authenticator code.", profilePage.getError());
totpPage.configure(totp.generate(totpPage.getTotpSecret())); totpPage.configure(totp.generate(totpPage.getTotpSecret()));
Assert.assertEquals("Mobile authenticator configured.", profilePage.getSuccess()); Assert.assertEquals("Mobile authenticator configured.", profilePage.getSuccess());
events.expectAccount(EventType.UPDATE_TOTP).assertEvent(); events.expectAccount(EventType.UPDATE_TOTP).assertEvent();
Assert.assertTrue(driver.getPageSource().contains("pficon-delete")); Assert.assertTrue(driver.getPageSource().contains("pficon-delete"));
totpPage.removeTotp(); totpPage.removeTotp();
events.expectAccount(EventType.REMOVE_TOTP).assertEvent(); events.expectAccount(EventType.REMOVE_TOTP).assertEvent();
} }
@Test @Test
public void changeProfileNoAccess() throws Exception { public void changeProfileNoAccess() throws Exception {
profilePage.open(); profilePage.open();
loginPage.login("test-user-no-access@localhost", "password"); loginPage.login("test-user-no-access@localhost", "password");
events.expectLogin().client("account").user(keycloakRule.getUser("test", "test-user-no-access@localhost").getId()) events.expectLogin().client("account").user(keycloakRule.getUser("test", "test-user-no-access@localhost").getId())
.detail(Details.USERNAME, "test-user-no-access@localhost") .detail(Details.USERNAME, "test-user-no-access@localhost")
.detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT).assertEvent(); .detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT).assertEvent();
Assert.assertTrue(errorPage.isCurrent()); Assert.assertTrue(errorPage.isCurrent());
Assert.assertEquals("No access", errorPage.getError()); Assert.assertEquals("No access", errorPage.getError());
} }
@Test @Test
public void viewLog() { public void viewLog() {
keycloakRule.update(new KeycloakSetup() { keycloakRule.update(new KeycloakSetup() {
@Override @Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
appRealm.setEventsEnabled(true); appRealm.setEventsEnabled(true);
} }
}); });
try { try {
List<Event> expectedEvents = new LinkedList<Event>(); List<Event> expectedEvents = new LinkedList<Event>();
loginPage.open(); loginPage.open();
loginPage.clickRegister(); loginPage.clickRegister();
registerPage.register("view", "log", "view-log@localhost", "view-log", "password", "password"); registerPage.register("view", "log", "view-log@localhost", "view-log", "password", "password");
expectedEvents.add(events.poll()); expectedEvents.add(events.poll());
expectedEvents.add(events.poll()); expectedEvents.add(events.poll());
profilePage.open(); profilePage.open();
profilePage.updateProfile("view", "log2", "view-log@localhost"); profilePage.updateProfile("view", "log2", "view-log@localhost");
expectedEvents.add(events.poll()); expectedEvents.add(events.poll());
logPage.open(); logPage.open();
Assert.assertTrue(logPage.isCurrent()); Assert.assertTrue(logPage.isCurrent());
List<List<String>> actualEvents = logPage.getEvents(); List<List<String>> actualEvents = logPage.getEvents();
Assert.assertEquals(expectedEvents.size(), actualEvents.size()); Assert.assertEquals(expectedEvents.size(), actualEvents.size());
for (Event e : expectedEvents) { for (Event e : expectedEvents) {
boolean match = false; boolean match = false;
for (List<String> a : logPage.getEvents()) { for (List<String> a : logPage.getEvents()) {
if (e.getType().toString().replace('_', ' ').toLowerCase().equals(a.get(1)) && if (e.getType().toString().replace('_', ' ').toLowerCase().equals(a.get(1)) &&
e.getIpAddress().equals(a.get(2)) && e.getIpAddress().equals(a.get(2)) &&
e.getClientId().equals(a.get(3))) { e.getClientId().equals(a.get(3))) {
match = true; match = true;
break; break;
} }
} }
if (!match) { if (!match) {
Assert.fail("Event not found " + e.getType()); Assert.fail("Event not found " + e.getType());
} }
} }
} finally { } finally {
keycloakRule.update(new KeycloakSetup() { keycloakRule.update(new KeycloakSetup() {
@Override @Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
appRealm.setEventsEnabled(false); appRealm.setEventsEnabled(false);
} }
}); });
} }
} }
@Test @Test
public void sessions() { public void sessions() {
loginPage.open(); loginPage.open();
loginPage.clickRegister(); loginPage.clickRegister();
registerPage.register("view", "sessions", "view-sessions@localhost", "view-sessions", "password", "password"); registerPage.register("view", "sessions", "view-sessions@localhost", "view-sessions", "password", "password");
Event registerEvent = events.expectRegister("view-sessions", "view-sessions@localhost").assertEvent(); Event registerEvent = events.expectRegister("view-sessions", "view-sessions@localhost").assertEvent();
String userId = registerEvent.getUserId(); String userId = registerEvent.getUserId();
events.expectLogin().user(userId).detail(Details.USERNAME, "view-sessions").assertEvent(); events.expectLogin().user(userId).detail(Details.USERNAME, "view-sessions").assertEvent();
sessionsPage.open(); sessionsPage.open();
Assert.assertTrue(sessionsPage.isCurrent()); Assert.assertTrue(sessionsPage.isCurrent());
List<List<String>> sessions = sessionsPage.getSessions(); List<List<String>> sessions = sessionsPage.getSessions();
Assert.assertEquals(1, sessions.size()); Assert.assertEquals(1, sessions.size());
Assert.assertEquals("127.0.0.1", sessions.get(0).get(0)); Assert.assertEquals("127.0.0.1", sessions.get(0).get(0));
// Create second session // Create second session
WebDriver driver2 = WebRule.createWebDriver(); WebDriver driver2 = WebRule.createWebDriver();
try { try {
OAuthClient oauth2 = new OAuthClient(driver2); OAuthClient oauth2 = new OAuthClient(driver2);
oauth2.state("mystate"); oauth2.state("mystate");
oauth2.doLogin("view-sessions", "password"); oauth2.doLogin("view-sessions", "password");
Event login2Event = events.expectLogin().user(userId).detail(Details.USERNAME, "view-sessions").assertEvent(); Event login2Event = events.expectLogin().user(userId).detail(Details.USERNAME, "view-sessions").assertEvent();
sessionsPage.open(); sessionsPage.open();
sessions = sessionsPage.getSessions(); sessions = sessionsPage.getSessions();
Assert.assertEquals(2, sessions.size()); Assert.assertEquals(2, sessions.size());
sessionsPage.logoutAll(); sessionsPage.logoutAll();
events.expectLogout(registerEvent.getSessionId()); events.expectLogout(registerEvent.getSessionId());
events.expectLogout(login2Event.getSessionId()); events.expectLogout(login2Event.getSessionId());
} finally { } finally {
driver2.close(); driver2.close();
} }
} }
} }

View file

@ -30,11 +30,13 @@ import org.keycloak.Version;
import org.keycloak.admin.client.Keycloak; import org.keycloak.admin.client.Keycloak;
import org.keycloak.constants.AdapterConstants; import org.keycloak.constants.AdapterConstants;
import org.keycloak.models.ApplicationModel; import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.Constants; import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel; import org.keycloak.models.UserSessionModel;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.protocol.oidc.OIDCLoginProtocolService; import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
import org.keycloak.protocol.oidc.TokenManager; import org.keycloak.protocol.oidc.TokenManager;
import org.keycloak.representations.AccessToken; import org.keycloak.representations.AccessToken;
@ -140,8 +142,10 @@ public class AdapterTestStrategy extends ExternalResource {
ApplicationModel adminConsole = adminRealm.getApplicationByName(Constants.ADMIN_CONSOLE_APPLICATION); ApplicationModel adminConsole = adminRealm.getApplicationByName(Constants.ADMIN_CONSOLE_APPLICATION);
TokenManager tm = new TokenManager(); TokenManager tm = new TokenManager();
UserModel admin = session.users().getUserByUsername("admin", adminRealm); UserModel admin = session.users().getUserByUsername("admin", adminRealm);
UserSessionModel userSession = session.sessions().createUserSession(adminRealm, admin, "admin", null, "form", false, null, null); ClientSessionModel clientSession = session.sessions().createClientSession(adminRealm, adminConsole);
AccessToken token = tm.createClientAccessToken(session, TokenManager.getAccess(null, adminConsole, admin), adminRealm, adminConsole, admin, userSession, null); clientSession.setNote(OIDCLoginProtocol.ISSUER, AUTH_SERVER_URL + "/realms/master");
UserSessionModel userSession = session.sessions().createUserSession(adminRealm, admin, "admin", null, "form", false);
AccessToken token = tm.createClientAccessToken(session, TokenManager.getAccess(null, adminConsole, admin), adminRealm, adminConsole, admin, userSession, clientSession);
return tm.encodeToken(adminRealm, token); return tm.encodeToken(adminRealm, token);
} finally { } finally {
keycloakRule.stopSession(session, true); keycloakRule.stopSession(session, true);

View file

@ -27,11 +27,13 @@ import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.keycloak.OAuth2Constants; import org.keycloak.OAuth2Constants;
import org.keycloak.models.ApplicationModel; import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.Constants; import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel; import org.keycloak.models.UserSessionModel;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.protocol.oidc.OIDCLoginProtocolService; import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
import org.keycloak.protocol.oidc.TokenManager; import org.keycloak.protocol.oidc.TokenManager;
import org.keycloak.representations.AccessToken; import org.keycloak.representations.AccessToken;
@ -86,8 +88,10 @@ public class RelativeUriAdapterTest {
ApplicationModel adminConsole = adminRealm.getApplicationByName(Constants.ADMIN_CONSOLE_APPLICATION); ApplicationModel adminConsole = adminRealm.getApplicationByName(Constants.ADMIN_CONSOLE_APPLICATION);
TokenManager tm = new TokenManager(); TokenManager tm = new TokenManager();
UserModel admin = session.users().getUserByUsername("admin", adminRealm); UserModel admin = session.users().getUserByUsername("admin", adminRealm);
UserSessionModel userSession = session.sessions().createUserSession(adminRealm, admin, "user", null, "form", false, null, null); ClientSessionModel clientSession = session.sessions().createClientSession(realm, adminConsole);
AccessToken token = tm.createClientAccessToken(session, tm.getAccess(null, adminConsole, admin), adminRealm, adminConsole, admin, userSession, null); clientSession.setNote(OIDCLoginProtocol.ISSUER, "http://localhost:8081/auth/realms/master");
UserSessionModel userSession = session.sessions().createUserSession(adminRealm, admin, "user", null, "form", false);
AccessToken token = tm.createClientAccessToken(session, tm.getAccess(null, adminConsole, admin), adminRealm, adminConsole, admin, userSession, clientSession);
adminToken = tm.encodeToken(adminRealm, token); adminToken = tm.encodeToken(adminRealm, token);
} }

View file

@ -26,11 +26,13 @@ import org.junit.ClassRule;
import org.junit.Test; import org.junit.Test;
import org.keycloak.Config; import org.keycloak.Config;
import org.keycloak.models.ApplicationModel; import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.Constants; import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel; import org.keycloak.models.UserSessionModel;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.protocol.oidc.TokenManager; import org.keycloak.protocol.oidc.TokenManager;
import org.keycloak.representations.AccessToken; import org.keycloak.representations.AccessToken;
import org.keycloak.representations.idm.ApplicationRepresentation; import org.keycloak.representations.idm.ApplicationRepresentation;
@ -78,8 +80,10 @@ public class AdminAPITest {
ApplicationModel adminConsole = adminRealm.getApplicationByName(Constants.ADMIN_CONSOLE_APPLICATION); ApplicationModel adminConsole = adminRealm.getApplicationByName(Constants.ADMIN_CONSOLE_APPLICATION);
TokenManager tm = new TokenManager(); TokenManager tm = new TokenManager();
UserModel admin = session.users().getUserByUsername("admin", adminRealm); UserModel admin = session.users().getUserByUsername("admin", adminRealm);
UserSessionModel userSession = session.sessions().createUserSession(adminRealm, admin, "admin", null, "form", false, null, null); ClientSessionModel clientSession = session.sessions().createClientSession(adminRealm, adminConsole);
AccessToken token = tm.createClientAccessToken(session, tm.getAccess(null, adminConsole, admin), adminRealm, adminConsole, admin, userSession, null); clientSession.setNote(OIDCLoginProtocol.ISSUER, "http://localhost:8081/auth/realms/master");
UserSessionModel userSession = session.sessions().createUserSession(adminRealm, admin, "admin", null, "form", false);
AccessToken token = tm.createClientAccessToken(session, tm.getAccess(null, adminConsole, admin), adminRealm, adminConsole, admin, userSession, clientSession);
return tm.encodeToken(adminRealm, token); return tm.encodeToken(adminRealm, token);
} finally { } finally {
keycloakRule.stopSession(session, true); keycloakRule.stopSession(session, true);

View file

@ -1,474 +1,478 @@
package org.keycloak.testsuite.saml; package org.keycloak.testsuite.saml;
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput; import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput;
import org.junit.Assert; import org.junit.Assert;
import org.junit.ClassRule; import org.junit.ClassRule;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.keycloak.Config; import org.keycloak.Config;
import org.keycloak.models.ApplicationModel; import org.keycloak.models.ApplicationModel;
import org.keycloak.models.Constants; import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.Constants;
import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.UserModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.UserSessionModel; import org.keycloak.models.UserModel;
import org.keycloak.protocol.oidc.TokenManager; import org.keycloak.models.UserSessionModel;
import org.keycloak.protocol.saml.mappers.AttributeStatementHelper; import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.protocol.saml.mappers.HardcodedAttributeMapper; import org.keycloak.protocol.oidc.TokenManager;
import org.keycloak.protocol.saml.mappers.HardcodedRole; import org.keycloak.protocol.saml.mappers.AttributeStatementHelper;
import org.keycloak.protocol.saml.mappers.RoleListMapper; import org.keycloak.protocol.saml.mappers.HardcodedAttributeMapper;
import org.keycloak.protocol.saml.mappers.RoleNameMapper; import org.keycloak.protocol.saml.mappers.HardcodedRole;
import org.keycloak.representations.AccessToken; import org.keycloak.protocol.saml.mappers.RoleListMapper;
import org.keycloak.services.managers.RealmManager; import org.keycloak.protocol.saml.mappers.RoleNameMapper;
import org.keycloak.services.resources.admin.AdminRoot; import org.keycloak.representations.AccessToken;
import org.keycloak.testsuite.pages.LoginPage; import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.rule.KeycloakRule; import org.keycloak.services.resources.admin.AdminRoot;
import org.keycloak.testsuite.rule.WebResource; import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.rule.WebRule; import org.keycloak.testsuite.rule.KeycloakRule;
import org.openqa.selenium.WebDriver; import org.keycloak.testsuite.rule.WebResource;
import org.picketlink.common.constants.JBossSAMLURIConstants; import org.keycloak.testsuite.rule.WebRule;
import org.picketlink.identity.federation.api.saml.v2.response.SAML2Response; import org.openqa.selenium.WebDriver;
import org.picketlink.identity.federation.core.saml.v2.constants.X500SAMLProfileConstants; import org.picketlink.common.constants.JBossSAMLURIConstants;
import org.picketlink.identity.federation.saml.v2.assertion.AssertionType; import org.picketlink.identity.federation.api.saml.v2.response.SAML2Response;
import org.picketlink.identity.federation.saml.v2.assertion.AttributeStatementType; import org.picketlink.identity.federation.core.saml.v2.constants.X500SAMLProfileConstants;
import org.picketlink.identity.federation.saml.v2.assertion.AttributeType; import org.picketlink.identity.federation.saml.v2.assertion.AssertionType;
import org.picketlink.identity.federation.saml.v2.protocol.ResponseType; import org.picketlink.identity.federation.saml.v2.assertion.AttributeStatementType;
import org.picketlink.identity.federation.web.util.PostBindingUtil; import org.picketlink.identity.federation.saml.v2.assertion.AttributeType;
import org.picketlink.identity.federation.saml.v2.protocol.ResponseType;
import javax.servlet.ServletException; import org.picketlink.identity.federation.web.util.PostBindingUtil;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServlet;
import javax.ws.rs.client.Client; import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.client.ClientBuilder; import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.client.ClientRequestContext; import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientRequestFilter; import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity; import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.WebTarget; import javax.ws.rs.client.ClientRequestFilter;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType; import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response; import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.MediaType;
import java.io.ByteArrayInputStream; import javax.ws.rs.core.Response;
import java.io.IOException; import javax.ws.rs.core.UriBuilder;
import java.io.InputStream; import java.io.ByteArrayInputStream;
import java.io.IOException;
/** import java.io.InputStream;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ /**
*/ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
public class SamlBindingTest { * @version $Revision: 1 $
*/
@ClassRule public class SamlBindingTest {
public static SamlKeycloakRule keycloakRule = new SamlKeycloakRule() {
@Override @ClassRule
public void initWars() { public static SamlKeycloakRule keycloakRule = new SamlKeycloakRule() {
ClassLoader classLoader = SamlBindingTest.class.getClassLoader(); @Override
public void initWars() {
initializeSamlSecuredWar("/saml/simple-post", "/sales-post", "post.war", classLoader); ClassLoader classLoader = SamlBindingTest.class.getClassLoader();
initializeSamlSecuredWar("/saml/signed-post", "/sales-post-sig", "post-sig.war", classLoader);
initializeSamlSecuredWar("/saml/signed-post-email", "/sales-post-sig-email", "post-sig-email.war", classLoader); initializeSamlSecuredWar("/saml/simple-post", "/sales-post", "post.war", classLoader);
initializeSamlSecuredWar("/saml/signed-post-transient", "/sales-post-sig-transient", "post-sig-transient.war", classLoader); initializeSamlSecuredWar("/saml/signed-post", "/sales-post-sig", "post-sig.war", classLoader);
initializeSamlSecuredWar("/saml/signed-post-persistent", "/sales-post-sig-persistent", "post-sig-persistent.war", classLoader); initializeSamlSecuredWar("/saml/signed-post-email", "/sales-post-sig-email", "post-sig-email.war", classLoader);
initializeSamlSecuredWar("/saml/signed-metadata", "/sales-metadata", "post-metadata.war", classLoader); initializeSamlSecuredWar("/saml/signed-post-transient", "/sales-post-sig-transient", "post-sig-transient.war", classLoader);
initializeSamlSecuredWar("/saml/signed-get", "/employee-sig", "employee-sig.war", classLoader); initializeSamlSecuredWar("/saml/signed-post-persistent", "/sales-post-sig-persistent", "post-sig-persistent.war", classLoader);
//initializeSamlSecuredWar("/saml/simple-get", "/employee", "employee.war", classLoader); initializeSamlSecuredWar("/saml/signed-metadata", "/sales-metadata", "post-metadata.war", classLoader);
initializeSamlSecuredWar("/saml/signed-front-get", "/employee-sig-front", "employee-sig-front.war", classLoader); initializeSamlSecuredWar("/saml/signed-get", "/employee-sig", "employee-sig.war", classLoader);
initializeSamlSecuredWar("/saml/bad-client-signed-post", "/bad-client-sales-post-sig", "bad-client-post-sig.war", classLoader); //initializeSamlSecuredWar("/saml/simple-get", "/employee", "employee.war", classLoader);
initializeSamlSecuredWar("/saml/bad-realm-signed-post", "/bad-realm-sales-post-sig", "bad-realm-post-sig.war", classLoader); initializeSamlSecuredWar("/saml/signed-front-get", "/employee-sig-front", "employee-sig-front.war", classLoader);
initializeSamlSecuredWar("/saml/encrypted-post", "/sales-post-enc", "post-enc.war", classLoader); initializeSamlSecuredWar("/saml/bad-client-signed-post", "/bad-client-sales-post-sig", "bad-client-post-sig.war", classLoader);
uploadSP(); initializeSamlSecuredWar("/saml/bad-realm-signed-post", "/bad-realm-sales-post-sig", "bad-realm-post-sig.war", classLoader);
server.getServer().deploy(createDeploymentInfo("employee.war", "/employee", SamlSPFacade.class)); initializeSamlSecuredWar("/saml/encrypted-post", "/sales-post-enc", "post-enc.war", classLoader);
uploadSP();
server.getServer().deploy(createDeploymentInfo("employee.war", "/employee", SamlSPFacade.class));
}
@Override }
public String getRealmJson() {
return "/saml/testsaml.json"; @Override
} public String getRealmJson() {
}; return "/saml/testsaml.json";
}
public static class SamlSPFacade extends HttpServlet { };
public static String samlResponse;
public static class SamlSPFacade extends HttpServlet {
@Override public static String samlResponse;
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
handler(req, resp); @Override
} protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
handler(req, resp);
@Override }
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
handler(req, resp); @Override
} protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
handler(req, resp);
private void handler(HttpServletRequest req, HttpServletResponse resp) { }
System.out.println("********* HERE ******");
if (req.getParameterMap().isEmpty()) { private void handler(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("redirecting"); System.out.println("********* HERE ******");
resp.setStatus(302); if (req.getParameterMap().isEmpty()) {
resp.setHeader("Location", "http://localhost:8081/auth/realms/demo/protocol/saml?SAMLRequest=jVJbT8IwFP4rS99HuwluNIwEIUYSLwugD76Y2h2kSdfOng7l31uGRn0ATfrQ9HznfJfTEYpaN3zS%2Bo1ZwGsL6KP3WhvkXaEgrTPcClTIjagBuZd8Obm55mmP8cZZb6XV5NByGiwQwXllDYkmX9epNdjW4JbgtkrC%2FeK6IBvvG06ptlLojUXPc5YnFOpG2x0AJdEsaFRG7PuPoUWwQx0IXSOtoLb0SynduyLRpXUSOs8FWQuNQKL5rCDz2VO%2FymEgIY2zlJ3H%2FSx9jkU%2BzOK0ys8yNmSSsUEAYxnsqC18tyO2MDfohfEFSVkyiNlZzM5XacrDSbJePug%2Fkqj8FHKhTKXMy%2BnIng8g5FerVRmXd8sViR7AYec8AMh4tPfDO3L3Y2%2F%2F3cT4j7BH9Mf8A1nDb8PA%2Bay0WsldNNHavk1D1D5k4V0LXbi18MclJL2ke1FVvO6gvDXYgFRrBRWh4wPp7z85%2FgA%3D"); System.out.println("redirecting");
return; resp.setStatus(302);
} resp.setHeader("Location", "http://localhost:8081/auth/realms/demo/protocol/saml?SAMLRequest=jVJbT8IwFP4rS99HuwluNIwEIUYSLwugD76Y2h2kSdfOng7l31uGRn0ATfrQ9HznfJfTEYpaN3zS%2Bo1ZwGsL6KP3WhvkXaEgrTPcClTIjagBuZd8Obm55mmP8cZZb6XV5NByGiwQwXllDYkmX9epNdjW4JbgtkrC%2FeK6IBvvG06ptlLojUXPc5YnFOpG2x0AJdEsaFRG7PuPoUWwQx0IXSOtoLb0SynduyLRpXUSOs8FWQuNQKL5rCDz2VO%2FymEgIY2zlJ3H%2FSx9jkU%2BzOK0ys8yNmSSsUEAYxnsqC18tyO2MDfohfEFSVkyiNlZzM5XacrDSbJePug%2Fkqj8FHKhTKXMy%2BnIng8g5FerVRmXd8sViR7AYec8AMh4tPfDO3L3Y2%2F%2F3cT4j7BH9Mf8A1nDb8PA%2Bay0WsldNNHavk1D1D5k4V0LXbi18MclJL2ke1FVvO6gvDXYgFRrBRWh4wPp7z85%2FgA%3D");
System.out.println("received response"); return;
samlResponse = req.getParameter("SAMLResponse"); }
} System.out.println("received response");
} samlResponse = req.getParameter("SAMLResponse");
}
@Rule }
public WebRule webRule = new WebRule(this);
@WebResource @Rule
protected WebDriver driver; public WebRule webRule = new WebRule(this);
@WebResource @WebResource
protected LoginPage loginPage; protected WebDriver driver;
@WebResource
//@Test protected LoginPage loginPage;
public void runit() throws Exception {
Thread.sleep(10000000); //@Test
} public void runit() throws Exception {
Thread.sleep(10000000);
protected void checkLoggedOut(String mainUrl) { }
String pageSource = driver.getPageSource();
System.out.println("*** logout pagesouce ***"); protected void checkLoggedOut(String mainUrl) {
System.out.println(pageSource); String pageSource = driver.getPageSource();
System.out.println("driver url: " + driver.getCurrentUrl()); System.out.println("*** logout pagesouce ***");
Assert.assertTrue(pageSource.contains("request-path: /logout.jsp")); System.out.println(pageSource);
driver.navigate().to(mainUrl); System.out.println("driver url: " + driver.getCurrentUrl());
Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml")); Assert.assertTrue(pageSource.contains("request-path: /logout.jsp"));
} driver.navigate().to(mainUrl);
Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
}
@Test
public void testPostSimpleLoginLogout() {
driver.navigate().to("http://localhost:8081/sales-post/"); @Test
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml"); public void testPostSimpleLoginLogout() {
loginPage.login("bburke", "password"); driver.navigate().to("http://localhost:8081/sales-post/");
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post/"); Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
System.out.println(driver.getPageSource()); loginPage.login("bburke", "password");
Assert.assertTrue(driver.getPageSource().contains("bburke")); Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post/");
driver.navigate().to("http://localhost:8081/sales-post?GLO=true"); System.out.println(driver.getPageSource());
checkLoggedOut("http://localhost:8081/sales-post/"); Assert.assertTrue(driver.getPageSource().contains("bburke"));
} driver.navigate().to("http://localhost:8081/sales-post?GLO=true");
@Test checkLoggedOut("http://localhost:8081/sales-post/");
public void testPostSignedLoginLogout() { }
driver.navigate().to("http://localhost:8081/sales-post-sig/"); @Test
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml"); public void testPostSignedLoginLogout() {
loginPage.login("bburke", "password"); driver.navigate().to("http://localhost:8081/sales-post-sig/");
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig/"); Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
Assert.assertTrue(driver.getPageSource().contains("bburke")); loginPage.login("bburke", "password");
driver.navigate().to("http://localhost:8081/sales-post-sig?GLO=true"); Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig/");
checkLoggedOut("http://localhost:8081/sales-post-sig/"); Assert.assertTrue(driver.getPageSource().contains("bburke"));
driver.navigate().to("http://localhost:8081/sales-post-sig?GLO=true");
} checkLoggedOut("http://localhost:8081/sales-post-sig/");
@Test
public void testPostSignedLoginLogoutTransientNameID() { }
driver.navigate().to("http://localhost:8081/sales-post-sig-transient/"); @Test
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml"); public void testPostSignedLoginLogoutTransientNameID() {
loginPage.login("bburke", "password"); driver.navigate().to("http://localhost:8081/sales-post-sig-transient/");
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig-transient/"); Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
System.out.println(driver.getPageSource()); loginPage.login("bburke", "password");
Assert.assertFalse(driver.getPageSource().contains("bburke")); Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig-transient/");
Assert.assertTrue(driver.getPageSource().contains("principal=G-")); System.out.println(driver.getPageSource());
driver.navigate().to("http://localhost:8081/sales-post-sig-transient?GLO=true"); Assert.assertFalse(driver.getPageSource().contains("bburke"));
checkLoggedOut("http://localhost:8081/sales-post-sig-transient/"); Assert.assertTrue(driver.getPageSource().contains("principal=G-"));
driver.navigate().to("http://localhost:8081/sales-post-sig-transient?GLO=true");
} checkLoggedOut("http://localhost:8081/sales-post-sig-transient/");
@Test
public void testPostSignedLoginLogoutPersistentNameID() { }
driver.navigate().to("http://localhost:8081/sales-post-sig-persistent/"); @Test
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml"); public void testPostSignedLoginLogoutPersistentNameID() {
loginPage.login("bburke", "password"); driver.navigate().to("http://localhost:8081/sales-post-sig-persistent/");
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig-persistent/"); Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
System.out.println(driver.getPageSource()); loginPage.login("bburke", "password");
Assert.assertFalse(driver.getPageSource().contains("bburke")); Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig-persistent/");
Assert.assertTrue(driver.getPageSource().contains("principal=G-")); System.out.println(driver.getPageSource());
driver.navigate().to("http://localhost:8081/sales-post-sig-persistent?GLO=true"); Assert.assertFalse(driver.getPageSource().contains("bburke"));
checkLoggedOut("http://localhost:8081/sales-post-sig-persistent/"); Assert.assertTrue(driver.getPageSource().contains("principal=G-"));
driver.navigate().to("http://localhost:8081/sales-post-sig-persistent?GLO=true");
} checkLoggedOut("http://localhost:8081/sales-post-sig-persistent/");
@Test
public void testPostSignedLoginLogoutEmailNameID() { }
driver.navigate().to("http://localhost:8081/sales-post-sig-email/"); @Test
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml"); public void testPostSignedLoginLogoutEmailNameID() {
loginPage.login("bburke", "password"); driver.navigate().to("http://localhost:8081/sales-post-sig-email/");
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig-email/"); Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
System.out.println(driver.getPageSource()); loginPage.login("bburke", "password");
Assert.assertTrue(driver.getPageSource().contains("principal=bburke@redhat.com")); Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig-email/");
driver.navigate().to("http://localhost:8081/sales-post-sig-email?GLO=true"); System.out.println(driver.getPageSource());
checkLoggedOut("http://localhost:8081/sales-post-sig-email/"); Assert.assertTrue(driver.getPageSource().contains("principal=bburke@redhat.com"));
driver.navigate().to("http://localhost:8081/sales-post-sig-email?GLO=true");
} checkLoggedOut("http://localhost:8081/sales-post-sig-email/");
}
@Test
public void testAttributes() throws Exception {
// this test has a hardcoded SAMLRequest and we hack a SP face servlet to get the SAMLResponse so we can look @Test
// at the assertions sent. This is because Picketlink, AFAICT, does not give you any way to get access to public void testAttributes() throws Exception {
// the assertion. // this test has a hardcoded SAMLRequest and we hack a SP face servlet to get the SAMLResponse so we can look
// at the assertions sent. This is because Picketlink, AFAICT, does not give you any way to get access to
{ // the assertion.
SamlSPFacade.samlResponse = null;
driver.navigate().to("http://localhost:8081/employee/"); {
Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml")); SamlSPFacade.samlResponse = null;
System.out.println(driver.getCurrentUrl()); driver.navigate().to("http://localhost:8081/employee/");
loginPage.login("bburke", "password"); Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee/"); System.out.println(driver.getCurrentUrl());
Assert.assertNotNull(SamlSPFacade.samlResponse); loginPage.login("bburke", "password");
SAML2Response saml2Response = new SAML2Response(); Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee/");
byte[] samlResponse = PostBindingUtil.base64Decode(SamlSPFacade.samlResponse); Assert.assertNotNull(SamlSPFacade.samlResponse);
ResponseType rt = saml2Response.getResponseType(new ByteArrayInputStream(samlResponse)); SAML2Response saml2Response = new SAML2Response();
Assert.assertTrue(rt.getAssertions().size() == 1); byte[] samlResponse = PostBindingUtil.base64Decode(SamlSPFacade.samlResponse);
AssertionType assertion = rt.getAssertions().get(0).getAssertion(); ResponseType rt = saml2Response.getResponseType(new ByteArrayInputStream(samlResponse));
Assert.assertTrue(rt.getAssertions().size() == 1);
// test attributes and roles AssertionType assertion = rt.getAssertions().get(0).getAssertion();
boolean email = false; // test attributes and roles
boolean phone = false;
boolean userRole = false; boolean email = false;
boolean managerRole = false; boolean phone = false;
for (AttributeStatementType statement : assertion.getAttributeStatements()) { boolean userRole = false;
for (AttributeStatementType.ASTChoiceType choice : statement.getAttributes()) { boolean managerRole = false;
AttributeType attr = choice.getAttribute(); for (AttributeStatementType statement : assertion.getAttributeStatements()) {
if (X500SAMLProfileConstants.EMAIL.getFriendlyName().equals(attr.getFriendlyName())) { for (AttributeStatementType.ASTChoiceType choice : statement.getAttributes()) {
Assert.assertEquals(X500SAMLProfileConstants.EMAIL.get(), attr.getName()); AttributeType attr = choice.getAttribute();
Assert.assertEquals(JBossSAMLURIConstants.ATTRIBUTE_FORMAT_URI.get(), attr.getNameFormat()); if (X500SAMLProfileConstants.EMAIL.getFriendlyName().equals(attr.getFriendlyName())) {
Assert.assertEquals(attr.getAttributeValue().get(0), "bburke@redhat.com"); Assert.assertEquals(X500SAMLProfileConstants.EMAIL.get(), attr.getName());
email = true; Assert.assertEquals(JBossSAMLURIConstants.ATTRIBUTE_FORMAT_URI.get(), attr.getNameFormat());
} else if (attr.getName().equals("phone")) { Assert.assertEquals(attr.getAttributeValue().get(0), "bburke@redhat.com");
Assert.assertEquals(JBossSAMLURIConstants.ATTRIBUTE_FORMAT_BASIC.get(), attr.getNameFormat()); email = true;
Assert.assertEquals(attr.getAttributeValue().get(0), "617"); } else if (attr.getName().equals("phone")) {
phone = true; Assert.assertEquals(JBossSAMLURIConstants.ATTRIBUTE_FORMAT_BASIC.get(), attr.getNameFormat());
} else if (attr.getName().equals("Role")) { Assert.assertEquals(attr.getAttributeValue().get(0), "617");
if (attr.getAttributeValue().get(0).equals("manager")) managerRole = true; phone = true;
if (attr.getAttributeValue().get(0).equals("user")) userRole = true; } else if (attr.getName().equals("Role")) {
} if (attr.getAttributeValue().get(0).equals("manager")) managerRole = true;
} if (attr.getAttributeValue().get(0).equals("user")) userRole = true;
}
} }
Assert.assertTrue(email); }
Assert.assertTrue(phone);
Assert.assertTrue(userRole); Assert.assertTrue(email);
Assert.assertTrue(managerRole); Assert.assertTrue(phone);
} Assert.assertTrue(userRole);
Assert.assertTrue(managerRole);
keycloakRule.update(new KeycloakRule.KeycloakSetup() { }
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) { keycloakRule.update(new KeycloakRule.KeycloakSetup() {
ApplicationModel app = appRealm.getApplicationByName("http://localhost:8081/employee/"); @Override
for (ProtocolMapperModel mapper : app.getProtocolMappers()) { public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
if (mapper.getName().equals("role-list")) { ApplicationModel app = appRealm.getApplicationByName("http://localhost:8081/employee/");
app.removeProtocolMapper(mapper); for (ProtocolMapperModel mapper : app.getProtocolMappers()) {
mapper.setId(null); if (mapper.getName().equals("role-list")) {
mapper.getConfig().put(RoleListMapper.SINGLE_ROLE_ATTRIBUTE, "true"); app.removeProtocolMapper(mapper);
mapper.getConfig().put(AttributeStatementHelper.SAML_ATTRIBUTE_NAME, "memberOf"); mapper.setId(null);
app.addProtocolMapper(mapper); mapper.getConfig().put(RoleListMapper.SINGLE_ROLE_ATTRIBUTE, "true");
} mapper.getConfig().put(AttributeStatementHelper.SAML_ATTRIBUTE_NAME, "memberOf");
} app.addProtocolMapper(mapper);
app.addProtocolMapper(HardcodedAttributeMapper.create("hardcoded-attribute", "hardcoded-attribute", "Basic", null, "hard", false, null)); }
app.addProtocolMapper(HardcodedRole.create("hardcoded-role", "hardcoded-role")); }
app.addProtocolMapper(RoleNameMapper.create("renamed-role", "manager", "el-jefe")); app.addProtocolMapper(HardcodedAttributeMapper.create("hardcoded-attribute", "hardcoded-attribute", "Basic", null, "hard", false, null));
app.addProtocolMapper(RoleNameMapper.create("renamed-employee-role", "http://localhost:8081/employee/.employee", "pee-on")); app.addProtocolMapper(HardcodedRole.create("hardcoded-role", "hardcoded-role"));
} app.addProtocolMapper(RoleNameMapper.create("renamed-role", "manager", "el-jefe"));
}, "demo"); app.addProtocolMapper(RoleNameMapper.create("renamed-employee-role", "http://localhost:8081/employee/.employee", "pee-on"));
}
System.out.println(">>>>>>>>>> single role attribute <<<<<<<<"); }, "demo");
{ System.out.println(">>>>>>>>>> single role attribute <<<<<<<<");
SamlSPFacade.samlResponse = null;
driver.navigate().to("http://localhost:8081/employee/"); {
System.out.println(driver.getCurrentUrl()); SamlSPFacade.samlResponse = null;
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee/"); driver.navigate().to("http://localhost:8081/employee/");
Assert.assertNotNull(SamlSPFacade.samlResponse); System.out.println(driver.getCurrentUrl());
SAML2Response saml2Response = new SAML2Response(); Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee/");
byte[] samlResponse = PostBindingUtil.base64Decode(SamlSPFacade.samlResponse); Assert.assertNotNull(SamlSPFacade.samlResponse);
ResponseType rt = saml2Response.getResponseType(new ByteArrayInputStream(samlResponse)); SAML2Response saml2Response = new SAML2Response();
Assert.assertTrue(rt.getAssertions().size() == 1); byte[] samlResponse = PostBindingUtil.base64Decode(SamlSPFacade.samlResponse);
AssertionType assertion = rt.getAssertions().get(0).getAssertion(); ResponseType rt = saml2Response.getResponseType(new ByteArrayInputStream(samlResponse));
Assert.assertTrue(rt.getAssertions().size() == 1);
// test attributes and roles AssertionType assertion = rt.getAssertions().get(0).getAssertion();
boolean userRole = false; // test attributes and roles
boolean managerRole = false;
boolean single = false; boolean userRole = false;
boolean hardcodedRole = false; boolean managerRole = false;
boolean hardcodedAttribute = false; boolean single = false;
boolean peeOn = false; boolean hardcodedRole = false;
for (AttributeStatementType statement : assertion.getAttributeStatements()) { boolean hardcodedAttribute = false;
for (AttributeStatementType.ASTChoiceType choice : statement.getAttributes()) { boolean peeOn = false;
AttributeType attr = choice.getAttribute(); for (AttributeStatementType statement : assertion.getAttributeStatements()) {
if (attr.getName().equals("memberOf")) { for (AttributeStatementType.ASTChoiceType choice : statement.getAttributes()) {
if (single) Assert.fail("too many role attributes"); AttributeType attr = choice.getAttribute();
single = true; if (attr.getName().equals("memberOf")) {
for (Object value : attr.getAttributeValue()) { if (single) Assert.fail("too many role attributes");
if (value.equals("el-jefe")) managerRole = true; single = true;
if (value.equals("user")) userRole = true; for (Object value : attr.getAttributeValue()) {
if (value.equals("hardcoded-role")) hardcodedRole = true; if (value.equals("el-jefe")) managerRole = true;
if (value.equals("pee-on")) peeOn = true; if (value.equals("user")) userRole = true;
} if (value.equals("hardcoded-role")) hardcodedRole = true;
} else if (attr.getName().equals("hardcoded-attribute")) { if (value.equals("pee-on")) peeOn = true;
hardcodedAttribute = true; }
Assert.assertEquals(attr.getAttributeValue().get(0), "hard"); } else if (attr.getName().equals("hardcoded-attribute")) {
} hardcodedAttribute = true;
} Assert.assertEquals(attr.getAttributeValue().get(0), "hard");
}
} }
Assert.assertTrue(single); }
Assert.assertTrue(hardcodedAttribute);
Assert.assertTrue(hardcodedRole); Assert.assertTrue(single);
Assert.assertTrue(peeOn); Assert.assertTrue(hardcodedAttribute);
Assert.assertTrue(userRole); Assert.assertTrue(hardcodedRole);
Assert.assertTrue(managerRole); Assert.assertTrue(peeOn);
} Assert.assertTrue(userRole);
} Assert.assertTrue(managerRole);
}
@Test }
public void testRedirectSignedLoginLogout() {
driver.navigate().to("http://localhost:8081/employee-sig/"); @Test
Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml")); public void testRedirectSignedLoginLogout() {
loginPage.login("bburke", "password"); driver.navigate().to("http://localhost:8081/employee-sig/");
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig/"); Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
Assert.assertTrue(driver.getPageSource().contains("bburke")); loginPage.login("bburke", "password");
driver.navigate().to("http://localhost:8081/employee-sig?GLO=true"); Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig/");
checkLoggedOut("http://localhost:8081/employee-sig/"); Assert.assertTrue(driver.getPageSource().contains("bburke"));
driver.navigate().to("http://localhost:8081/employee-sig?GLO=true");
} checkLoggedOut("http://localhost:8081/employee-sig/");
@Test }
public void testRedirectSignedLoginLogoutFrontNoSSO() {
driver.navigate().to("http://localhost:8081/employee-sig-front/"); @Test
Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml")); public void testRedirectSignedLoginLogoutFrontNoSSO() {
loginPage.login("bburke", "password"); driver.navigate().to("http://localhost:8081/employee-sig-front/");
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig-front/"); Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
Assert.assertTrue(driver.getPageSource().contains("bburke")); loginPage.login("bburke", "password");
driver.navigate().to("http://localhost:8081/employee-sig-front?GLO=true"); Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig-front/");
checkLoggedOut("http://localhost:8081/employee-sig-front/"); Assert.assertTrue(driver.getPageSource().contains("bburke"));
driver.navigate().to("http://localhost:8081/employee-sig-front?GLO=true");
} checkLoggedOut("http://localhost:8081/employee-sig-front/");
@Test }
public void testRedirectSignedLoginLogoutFront() {
// visit 1st app an logg in @Test
System.out.println("visit 1st app "); public void testRedirectSignedLoginLogoutFront() {
driver.navigate().to("http://localhost:8081/employee-sig/"); // visit 1st app an logg in
Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml")); System.out.println("visit 1st app ");
System.out.println("login to form"); driver.navigate().to("http://localhost:8081/employee-sig/");
loginPage.login("bburke", "password"); Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig/"); System.out.println("login to form");
Assert.assertTrue(driver.getPageSource().contains("bburke")); loginPage.login("bburke", "password");
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig/");
// visit 2nd app Assert.assertTrue(driver.getPageSource().contains("bburke"));
System.out.println("visit 2nd app ");
driver.navigate().to("http://localhost:8081/employee-sig-front/"); // visit 2nd app
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig-front/"); System.out.println("visit 2nd app ");
Assert.assertTrue(driver.getPageSource().contains("bburke")); driver.navigate().to("http://localhost:8081/employee-sig-front/");
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee-sig-front/");
// visit 3rd app Assert.assertTrue(driver.getPageSource().contains("bburke"));
System.out.println("visit 3rd app ");
driver.navigate().to("http://localhost:8081/sales-post-sig/"); // visit 3rd app
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig/"); System.out.println("visit 3rd app ");
Assert.assertTrue(driver.getPageSource().contains("bburke")); driver.navigate().to("http://localhost:8081/sales-post-sig/");
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-sig/");
// logout of first app Assert.assertTrue(driver.getPageSource().contains("bburke"));
System.out.println("GLO");
driver.navigate().to("http://localhost:8081/employee-sig?GLO=true"); // logout of first app
checkLoggedOut("http://localhost:8081/employee-sig/"); System.out.println("GLO");
driver.navigate().to("http://localhost:8081/employee-sig-front/"); driver.navigate().to("http://localhost:8081/employee-sig?GLO=true");
Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml")); checkLoggedOut("http://localhost:8081/employee-sig/");
driver.navigate().to("http://localhost:8081/sales-post-sig/"); driver.navigate().to("http://localhost:8081/employee-sig-front/");
Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml")); Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
driver.navigate().to("http://localhost:8081/sales-post-sig/");
} Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
@Test }
public void testPostEncryptedLoginLogout() {
driver.navigate().to("http://localhost:8081/sales-post-enc/"); @Test
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml"); public void testPostEncryptedLoginLogout() {
loginPage.login("bburke", "password"); driver.navigate().to("http://localhost:8081/sales-post-enc/");
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-enc/"); Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
Assert.assertTrue(driver.getPageSource().contains("bburke")); loginPage.login("bburke", "password");
driver.navigate().to("http://localhost:8081/sales-post-enc?GLO=true"); Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-post-enc/");
checkLoggedOut("http://localhost:8081/sales-post-enc/"); Assert.assertTrue(driver.getPageSource().contains("bburke"));
driver.navigate().to("http://localhost:8081/sales-post-enc?GLO=true");
} checkLoggedOut("http://localhost:8081/sales-post-enc/");
@Test
public void testPostBadClientSignature() { }
driver.navigate().to("http://localhost:8081/bad-client-sales-post-sig/"); @Test
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml"); public void testPostBadClientSignature() {
Assert.assertEquals(driver.getTitle(), "We're sorry..."); driver.navigate().to("http://localhost:8081/bad-client-sales-post-sig/");
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
} Assert.assertEquals(driver.getTitle(), "We're sorry...");
@Test }
public void testPostBadRealmSignature() {
driver.navigate().to("http://localhost:8081/bad-realm-sales-post-sig/"); @Test
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml"); public void testPostBadRealmSignature() {
loginPage.login("bburke", "password"); driver.navigate().to("http://localhost:8081/bad-realm-sales-post-sig/");
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/bad-realm-sales-post-sig/"); Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
Assert.assertTrue(driver.getPageSource().contains("null")); loginPage.login("bburke", "password");
} Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/bad-realm-sales-post-sig/");
Assert.assertTrue(driver.getPageSource().contains("null"));
private static String createToken() { }
KeycloakSession session = keycloakRule.startSession();
try { private static String createToken() {
RealmManager manager = new RealmManager(session); KeycloakSession session = keycloakRule.startSession();
try {
RealmModel adminRealm = manager.getRealm(Config.getAdminRealm()); RealmManager manager = new RealmManager(session);
ApplicationModel adminConsole = adminRealm.getApplicationByName(Constants.ADMIN_CONSOLE_APPLICATION);
TokenManager tm = new TokenManager(); RealmModel adminRealm = manager.getRealm(Config.getAdminRealm());
UserModel admin = session.users().getUserByUsername("admin", adminRealm); ApplicationModel adminConsole = adminRealm.getApplicationByName(Constants.ADMIN_CONSOLE_APPLICATION);
UserSessionModel userSession = session.sessions().createUserSession(adminRealm, admin, "admin", null, "form", false, null, null); TokenManager tm = new TokenManager();
AccessToken token = tm.createClientAccessToken(session, tm.getAccess(null, adminConsole, admin), adminRealm, adminConsole, admin, userSession, null); UserModel admin = session.users().getUserByUsername("admin", adminRealm);
return tm.encodeToken(adminRealm, token); ClientSessionModel clientSession = session.sessions().createClientSession(adminRealm, adminConsole);
} finally { clientSession.setNote(OIDCLoginProtocol.ISSUER, "http://localhost:8081/auth/realms/master");
keycloakRule.stopSession(session, true); UserSessionModel userSession = session.sessions().createUserSession(adminRealm, admin, "admin", null, "form", false);
} AccessToken token = tm.createClientAccessToken(session, tm.getAccess(null, adminConsole, admin), adminRealm, adminConsole, admin, userSession, clientSession);
} return tm.encodeToken(adminRealm, token);
} finally {
keycloakRule.stopSession(session, true);
@Test }
public void testMetadataPostSignedLoginLogout() throws Exception { }
driver.navigate().to("http://localhost:8081/sales-metadata/");
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml"); @Test
loginPage.login("bburke", "password"); public void testMetadataPostSignedLoginLogout() throws Exception {
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-metadata/");
String pageSource = driver.getPageSource(); driver.navigate().to("http://localhost:8081/sales-metadata/");
Assert.assertTrue(pageSource.contains("bburke")); Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/auth/realms/demo/protocol/saml");
driver.navigate().to("http://localhost:8081/sales-metadata?GLO=true"); loginPage.login("bburke", "password");
checkLoggedOut("http://localhost:8081/sales-metadata/"); Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/sales-metadata/");
String pageSource = driver.getPageSource();
} Assert.assertTrue(pageSource.contains("bburke"));
driver.navigate().to("http://localhost:8081/sales-metadata?GLO=true");
public static void uploadSP() { checkLoggedOut("http://localhost:8081/sales-metadata/");
String token = createToken();
final String authHeader = "Bearer " + token; }
ClientRequestFilter authFilter = new ClientRequestFilter() {
@Override public static void uploadSP() {
public void filter(ClientRequestContext requestContext) throws IOException { String token = createToken();
requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader); final String authHeader = "Bearer " + token;
} ClientRequestFilter authFilter = new ClientRequestFilter() {
}; @Override
Client client = ClientBuilder.newBuilder().register(authFilter).build(); public void filter(ClientRequestContext requestContext) throws IOException {
UriBuilder authBase = UriBuilder.fromUri("http://localhost:8081/auth"); requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader);
WebTarget adminRealms = client.target(AdminRoot.realmsUrl(authBase)); }
};
Client client = ClientBuilder.newBuilder().register(authFilter).build();
MultipartFormDataOutput formData = new MultipartFormDataOutput(); UriBuilder authBase = UriBuilder.fromUri("http://localhost:8081/auth");
InputStream is = SamlBindingTest.class.getResourceAsStream("/saml/sp-metadata.xml"); WebTarget adminRealms = client.target(AdminRoot.realmsUrl(authBase));
Assert.assertNotNull(is);
formData.addFormData("file", is, MediaType.APPLICATION_XML_TYPE);
MultipartFormDataOutput formData = new MultipartFormDataOutput();
WebTarget upload = adminRealms.path("demo/application-importers/saml2-entity-descriptor/upload"); InputStream is = SamlBindingTest.class.getResourceAsStream("/saml/sp-metadata.xml");
System.out.println(upload.getUri()); Assert.assertNotNull(is);
Response response = upload.request().post(Entity.entity(formData, MediaType.MULTIPART_FORM_DATA)); formData.addFormData("file", is, MediaType.APPLICATION_XML_TYPE);
Assert.assertEquals(204, response.getStatus());
response.close(); WebTarget upload = adminRealms.path("demo/application-importers/saml2-entity-descriptor/upload");
client.close(); System.out.println(upload.getUri());
} Response response = upload.request().post(Entity.entity(formData, MediaType.MULTIPART_FORM_DATA));
Assert.assertEquals(204, response.getStatus());
response.close();
} client.close();
}
}

View file

@ -2,6 +2,7 @@
"realm" : "demo", "realm" : "demo",
"resource" : "customer-db", "resource" : "customer-db",
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB", "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-server-url": "http://localhost:8081/auth",
"ssl-required" : "external", "ssl-required" : "external",
"bearer-only" : true, "bearer-only" : true,
"enable-cors" : true "enable-cors" : true

View file

@ -2,6 +2,7 @@
"realm" : "demo", "realm" : "demo",
"resource" : "customer-db", "resource" : "customer-db",
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB", "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-server-url": "http://localhost:8081/auth",
"ssl-required" : "external", "ssl-required" : "external",
"bearer-only" : true, "bearer-only" : true,
"enable-cors" : true "enable-cors" : true

View file

@ -2,6 +2,7 @@
"realm" : "demo", "realm" : "demo",
"resource" : "customer-db", "resource" : "customer-db",
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB", "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-server-url": "http://localhost:8081/auth",
"ssl-required" : "external", "ssl-required" : "external",
"bearer-only" : true, "bearer-only" : true,
"enable-cors" : true "enable-cors" : true

View file

@ -2,6 +2,7 @@
"realm" : "demo", "realm" : "demo",
"resource" : "customer-db", "resource" : "customer-db",
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB", "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-server-url": "http://localhost:8081/auth",
"ssl-required" : "external", "ssl-required" : "external",
"bearer-only" : true, "bearer-only" : true,
"enable-cors" : true "enable-cors" : true

View file

@ -166,7 +166,7 @@ public class OAuthClient {
public AccessToken verifyToken(String token) { public AccessToken verifyToken(String token) {
try { try {
return RSATokenVerifier.verifyToken(token, realmPublicKey, realm); return RSATokenVerifier.verifyToken(token, realmPublicKey, baseUrl + "/" + realm);
} catch (VerificationException e) { } catch (VerificationException e) {
throw new RuntimeException("Failed to verify token", e); throw new RuntimeException("Failed to verify token", e);
} }

View file

@ -2,6 +2,7 @@
"realm" : "demo", "realm" : "demo",
"resource" : "customer-db", "resource" : "customer-db",
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB", "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-server-url": "http://localhost:8081/auth",
"ssl-required" : "external", "ssl-required" : "external",
"bearer-only" : true, "bearer-only" : true,
"enable-cors" : true "enable-cors" : true

View file

@ -2,6 +2,7 @@
"realm" : "demo", "realm" : "demo",
"resource" : "customer-db", "resource" : "customer-db",
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB", "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-server-url": "http://localhost:8081/auth",
"ssl-required" : "external", "ssl-required" : "external",
"bearer-only" : true, "bearer-only" : true,
"enable-cors" : true "enable-cors" : true

View file

@ -2,8 +2,8 @@
"realm" : "demo", "realm" : "demo",
"resource" : "customer-db", "resource" : "customer-db",
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB", "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"auth-server-url": "http://localhost:8081/auth",
"ssl-required" : "external", "ssl-required" : "external",
"bearer-only" : true, "bearer-only" : true,
"enable-cors" : true "enable-cors" : true
}
}