parent
c51060ae34
commit
6112b25648
50 changed files with 1091 additions and 304 deletions
|
@ -40,6 +40,9 @@ import java.util.Map;
|
|||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class JsonWebToken implements Serializable, Token {
|
||||
public static final String AZP = "azp";
|
||||
public static final String SUBJECT = "sub";
|
||||
|
||||
@JsonProperty("jti")
|
||||
protected String id;
|
||||
|
||||
|
@ -53,11 +56,11 @@ public class JsonWebToken implements Serializable, Token {
|
|||
@JsonSerialize(using = StringOrArraySerializer.class)
|
||||
@JsonDeserialize(using = StringOrArrayDeserializer.class)
|
||||
protected String[] audience;
|
||||
@JsonProperty("sub")
|
||||
@JsonProperty(SUBJECT)
|
||||
protected String subject;
|
||||
@JsonProperty("typ")
|
||||
protected String type;
|
||||
@JsonProperty("azp")
|
||||
@JsonProperty(AZP)
|
||||
public String issuedFor;
|
||||
protected Map<String, Object> otherClaims = new HashMap<>();
|
||||
|
||||
|
@ -184,7 +187,7 @@ public class JsonWebToken implements Serializable, Token {
|
|||
this.iat = iat;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated int will overflow with values after 2038. Use {@link #iat(Long)} ()} instead.
|
||||
*/
|
||||
|
|
|
@ -3096,6 +3096,10 @@
|
|||
"label": "Add to userinfo",
|
||||
"tooltip": "Should the claim be added to the userinfo?"
|
||||
},
|
||||
"includeInIntrospection": {
|
||||
"label": "Add to token introspection",
|
||||
"tooltip": "Should the claim be added to the token introspection?"
|
||||
},
|
||||
"sectorIdentifierUri": {
|
||||
"label": "Sector Identifier URI",
|
||||
"tooltip": "Providers that use pairwise sub values and support Dynamic Client Registration SHOULD use the sector_identifier_uri parameter. It provides a way for a group of websites under common administrative control to have consistent pairwise sub values independent of the individual domain names. It also provides a way for Clients to change redirect_uri domains without having to reregister all their users."
|
||||
|
|
|
@ -315,6 +315,7 @@ public class UserSessionAdapter implements UserSessionModel {
|
|||
update(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionPersistenceState getPersistenceState() {
|
||||
return persistenceState;
|
||||
}
|
||||
|
|
|
@ -232,6 +232,11 @@ public class PersistentUserSessionAdapter implements OfflineUserSessionModel {
|
|||
return State.valueOf(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionPersistenceState getPersistenceState() {
|
||||
return SessionPersistenceState.PERSISTENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setState(State state) {
|
||||
String stateStr = state==null ? null : state.toString();
|
||||
|
|
|
@ -23,7 +23,6 @@ import org.keycloak.models.KeycloakSession;
|
|||
import org.keycloak.models.ModelIllegalStateException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.map.common.TimeAdapter;
|
||||
|
||||
|
@ -289,4 +288,9 @@ public class MapUserSessionAdapter extends AbstractUserSessionModel {
|
|||
public int hashCode() {
|
||||
return getId().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionPersistenceState getPersistenceState() {
|
||||
return entity.getPersistenceState();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ public interface UserSessionModel {
|
|||
|
||||
/**
|
||||
* Returns map where key is ID of the client (its UUID) and value is ID respective {@link AuthenticatedClientSessionModel} object.
|
||||
* @return
|
||||
* @return
|
||||
*/
|
||||
Map<String, AuthenticatedClientSessionModel> getAuthenticatedClientSessions();
|
||||
/**
|
||||
|
@ -135,6 +135,8 @@ public interface UserSessionModel {
|
|||
}
|
||||
}
|
||||
|
||||
SessionPersistenceState getPersistenceState();
|
||||
|
||||
/**
|
||||
* Flag used when creating user session
|
||||
*/
|
||||
|
|
|
@ -24,6 +24,12 @@ import org.keycloak.TokenVerifier;
|
|||
import org.keycloak.common.VerificationException;
|
||||
import org.keycloak.crypto.SignatureProvider;
|
||||
import org.keycloak.crypto.SignatureVerifierContext;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.EventBuilder;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.AuthenticatedClientSessionModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientSessionContext;
|
||||
import org.keycloak.models.ImpersonationSessionNote;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
|
@ -31,6 +37,8 @@ import org.keycloak.models.UserModel;
|
|||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.services.Urls;
|
||||
import org.keycloak.services.util.DefaultClientSessionContext;
|
||||
import org.keycloak.services.util.UserSessionUtil;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
|
@ -55,6 +63,7 @@ public class AccessTokenIntrospectionProvider implements TokenIntrospectionProvi
|
|||
public Response introspect(String token) {
|
||||
try {
|
||||
AccessToken accessToken = verifyAccessToken(token);
|
||||
accessToken = transformAccessToken(accessToken);
|
||||
ObjectNode tokenMetadata;
|
||||
|
||||
if (accessToken != null) {
|
||||
|
@ -106,6 +115,57 @@ public class AccessTokenIntrospectionProvider implements TokenIntrospectionProvi
|
|||
}
|
||||
}
|
||||
|
||||
private AccessToken transformAccessToken(AccessToken token) {
|
||||
if (token == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ClientModel client = realm.getClientByClientId(token.getIssuedFor());
|
||||
EventBuilder event = new EventBuilder(realm, session, session.getContext().getConnection())
|
||||
.event(EventType.INTROSPECT_TOKEN)
|
||||
.detail(Details.AUTH_METHOD, Details.VALIDATE_ACCESS_TOKEN);
|
||||
UserSessionModel userSession;
|
||||
try {
|
||||
userSession = UserSessionUtil.findValidSession(session, realm, token, event, client);
|
||||
} catch (Exception e) {
|
||||
logger.debugf("Can not get user session: %s", e.getMessage());
|
||||
// Backwards compatibility
|
||||
return token;
|
||||
}
|
||||
if (userSession.getUser() == null) {
|
||||
logger.debugf("User not found");
|
||||
// Backwards compatibility
|
||||
return token;
|
||||
}
|
||||
AuthenticatedClientSessionModel clientSession = userSession.getAuthenticatedClientSessionByClient(client.getId());
|
||||
ClientSessionContext clientSessionCtx = DefaultClientSessionContext.fromClientSessionScopeParameter(clientSession, session);
|
||||
AccessToken smallToken = getAccessTokenFromStoredData(token, userSession);
|
||||
return tokenManager.transformIntrospectionAccessToken(session, smallToken, userSession, clientSessionCtx);
|
||||
}
|
||||
|
||||
private AccessToken getAccessTokenFromStoredData(AccessToken token, UserSessionModel userSession) {
|
||||
// Copy just "basic" claims from the initial token. The same like filled in TokenManager.initToken. The rest should be possibly added by protocol mappers (only if configured for introspection response)
|
||||
AccessToken newToken = new AccessToken();
|
||||
newToken.id(token.getId());
|
||||
newToken.type(token.getType());
|
||||
newToken.subject(token.getSubject() != null ? token.getSubject() : userSession.getUser().getId());
|
||||
newToken.iat(token.getIat());
|
||||
newToken.exp(token.getExp());
|
||||
newToken.issuedFor(token.getIssuedFor());
|
||||
newToken.issuer(token.getIssuer());
|
||||
newToken.setNonce(token.getNonce());
|
||||
newToken.setScope(token.getScope());
|
||||
newToken.setAuth_time(token.getAuth_time());
|
||||
newToken.setSessionState(token.getSessionState());
|
||||
|
||||
// In the case of a refresh token, aud is a basic claim.
|
||||
newToken.audience(token.getAudience());
|
||||
|
||||
// The cnf is not a claim controlled by the protocol mapper.
|
||||
newToken.setConfirmation(token.getConfirmation());
|
||||
return newToken;
|
||||
}
|
||||
|
||||
protected AccessToken verifyAccessToken(String token) {
|
||||
AccessToken accessToken;
|
||||
|
||||
|
|
|
@ -133,29 +133,29 @@ public class OIDCLoginProtocolFactory extends AbstractLoginProtocolFactory {
|
|||
private Map<String, ProtocolMapperModel> builtins = new HashMap<>();
|
||||
|
||||
void initBuiltIns() {
|
||||
ProtocolMapperModel model;
|
||||
ProtocolMapperModel model;
|
||||
model = UserAttributeMapper.createClaimMapper(USERNAME,
|
||||
"username",
|
||||
"preferred_username", String.class.getSimpleName(),
|
||||
true, true);
|
||||
true, true, true);
|
||||
builtins.put(USERNAME, model);
|
||||
|
||||
model = UserAttributeMapper.createClaimMapper(EMAIL,
|
||||
"email",
|
||||
"email", "String",
|
||||
true, true);
|
||||
true, true, true);
|
||||
builtins.put(EMAIL, model);
|
||||
|
||||
model = UserAttributeMapper.createClaimMapper(GIVEN_NAME,
|
||||
"firstName",
|
||||
"given_name", "String",
|
||||
true, true);
|
||||
true, true, true);
|
||||
builtins.put(GIVEN_NAME, model);
|
||||
|
||||
model = UserAttributeMapper.createClaimMapper(FAMILY_NAME,
|
||||
"lastName",
|
||||
"family_name", "String",
|
||||
true, true);
|
||||
true, true, true);
|
||||
builtins.put(FAMILY_NAME, model);
|
||||
|
||||
createUserAttributeMapper(MIDDLE_NAME, "middleName", IDToken.MIDDLE_NAME, "String");
|
||||
|
@ -175,10 +175,10 @@ public class OIDCLoginProtocolFactory extends AbstractLoginProtocolFactory {
|
|||
model = UserPropertyMapper.createClaimMapper(EMAIL_VERIFIED,
|
||||
"emailVerified",
|
||||
"email_verified", "boolean",
|
||||
true, true);
|
||||
true, true, true);
|
||||
builtins.put(EMAIL_VERIFIED, model);
|
||||
|
||||
ProtocolMapperModel fullName = FullNameMapper.create(FULL_NAME, true, true, true);
|
||||
ProtocolMapperModel fullName = FullNameMapper.create(FULL_NAME, true, true, true, true);
|
||||
builtins.put(FULL_NAME, fullName);
|
||||
|
||||
ProtocolMapperModel address = AddressMapper.createAddressMapper();
|
||||
|
@ -187,19 +187,19 @@ public class OIDCLoginProtocolFactory extends AbstractLoginProtocolFactory {
|
|||
model = UserSessionNoteMapper.createClaimMapper(KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME,
|
||||
KerberosConstants.GSS_DELEGATION_CREDENTIAL,
|
||||
KerberosConstants.GSS_DELEGATION_CREDENTIAL, "String",
|
||||
true, false);
|
||||
true, false, true);
|
||||
builtins.put(KerberosConstants.GSS_DELEGATION_CREDENTIAL, model);
|
||||
|
||||
model = UserRealmRoleMappingMapper.create(null, REALM_ROLES, "realm_access.roles", true, false, true);
|
||||
model = UserRealmRoleMappingMapper.create(null, REALM_ROLES, "realm_access.roles", true, false, true, true);
|
||||
builtins.put(REALM_ROLES, model);
|
||||
|
||||
model = UserClientRoleMappingMapper.create(null, null, CLIENT_ROLES, "resource_access.${client_id}.roles", true, false, true);
|
||||
model = UserClientRoleMappingMapper.create(null, null, CLIENT_ROLES, "resource_access.${client_id}.roles", true, false, true, true);
|
||||
builtins.put(CLIENT_ROLES, model);
|
||||
|
||||
model = AudienceResolveProtocolMapper.createClaimMapper(AUDIENCE_RESOLVE);
|
||||
model = AudienceResolveProtocolMapper.createClaimMapper(AUDIENCE_RESOLVE, true, true);
|
||||
builtins.put(AUDIENCE_RESOLVE, model);
|
||||
|
||||
model = AllowedWebOriginsProtocolMapper.createClaimMapper(ALLOWED_WEB_ORIGINS);
|
||||
model = AllowedWebOriginsProtocolMapper.createClaimMapper(ALLOWED_WEB_ORIGINS, true, true);
|
||||
builtins.put(ALLOWED_WEB_ORIGINS, model);
|
||||
|
||||
builtins.put(IMPERSONATOR_ID.getDisplayName(), UserSessionNoteMapper.createUserSessionNoteMapper(IMPERSONATOR_ID));
|
||||
|
@ -207,14 +207,14 @@ public class OIDCLoginProtocolFactory extends AbstractLoginProtocolFactory {
|
|||
|
||||
model = UserAttributeMapper.createClaimMapper(UPN, "username",
|
||||
"upn", "String",
|
||||
true, true);
|
||||
true, true, true);
|
||||
builtins.put(UPN, model);
|
||||
|
||||
model = UserRealmRoleMappingMapper.create(null, GROUPS, GROUPS, true, true, true);
|
||||
model = UserRealmRoleMappingMapper.create(null, GROUPS, GROUPS, true, true, true, true);
|
||||
builtins.put(GROUPS, model);
|
||||
|
||||
if (Profile.isFeatureEnabled(Profile.Feature.STEP_UP_AUTHENTICATION)) {
|
||||
model = AcrProtocolMapper.create(ACR, true, true);
|
||||
model = AcrProtocolMapper.create(ACR, true, true, true);
|
||||
builtins.put(ACR, model);
|
||||
}
|
||||
}
|
||||
|
@ -223,7 +223,7 @@ public class OIDCLoginProtocolFactory extends AbstractLoginProtocolFactory {
|
|||
ProtocolMapperModel model = UserAttributeMapper.createClaimMapper(name,
|
||||
attrName,
|
||||
claimName, type,
|
||||
true, true, false);
|
||||
true, true, true, false);
|
||||
builtins.put(name, model);
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ import org.keycloak.models.utils.SessionExpirationUtils;
|
|||
import org.keycloak.models.utils.RoleUtils;
|
||||
import org.keycloak.protocol.ProtocolMapper;
|
||||
import org.keycloak.protocol.ProtocolMapperUtils;
|
||||
import org.keycloak.protocol.oidc.mappers.TokenIntrospectionTokenMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.OIDCAccessTokenMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.OIDCAccessTokenResponseMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.OIDCIDTokenMapper;
|
||||
|
@ -785,6 +786,17 @@ public class TokenManager {
|
|||
});
|
||||
}
|
||||
|
||||
public AccessToken transformIntrospectionAccessToken(KeycloakSession session, AccessToken token,
|
||||
UserSessionModel userSession, ClientSessionContext clientSessionCtx) {
|
||||
return ProtocolMapperUtils.getSortedProtocolMappers(session, clientSessionCtx, mapper -> mapper.getValue() instanceof TokenIntrospectionTokenMapper)
|
||||
.collect(new TokenCollector<AccessToken>(token) {
|
||||
@Override
|
||||
protected AccessToken applyMapper(AccessToken token, Map.Entry<ProtocolMapperModel, ProtocolMapper> mapper) {
|
||||
return ((TokenIntrospectionTokenMapper) mapper.getValue()).transformIntrospectionToken(token, mapper.getKey(), session, userSession, clientSessionCtx);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Map<String, Object> generateUserInfoClaims(AccessToken userInfo, UserModel userModel) {
|
||||
Map<String, Object> claims = new HashMap<>();
|
||||
claims.put("sub", userInfo.getSubject() == null? userModel.getId() : userInfo.getSubject());
|
||||
|
|
|
@ -24,7 +24,6 @@ import org.keycloak.TokenVerifier;
|
|||
import org.keycloak.common.ClientConnection;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.common.VerificationException;
|
||||
import org.keycloak.common.constants.ServiceAccountConstants;
|
||||
import org.keycloak.crypto.ContentEncryptionProvider;
|
||||
import org.keycloak.crypto.CekManagementProvider;
|
||||
import org.keycloak.crypto.KeyWrapper;
|
||||
|
@ -48,7 +47,6 @@ import org.keycloak.models.KeycloakSession;
|
|||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import org.keycloak.protocol.oidc.TokenManager;
|
||||
|
@ -59,15 +57,11 @@ import org.keycloak.services.Urls;
|
|||
import org.keycloak.services.clientpolicy.ClientPolicyException;
|
||||
import org.keycloak.services.clientpolicy.context.UserInfoRequestContext;
|
||||
import org.keycloak.services.managers.AppAuthManager;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
import org.keycloak.services.managers.UserSessionCrossDCManager;
|
||||
import org.keycloak.services.managers.UserSessionManager;
|
||||
import org.keycloak.services.resources.Cors;
|
||||
import org.keycloak.services.util.DPoPUtil;
|
||||
import org.keycloak.services.util.DefaultClientSessionContext;
|
||||
import org.keycloak.services.util.MtlsHoKTokenUtil;
|
||||
import org.keycloak.sessions.AuthenticationSessionModel;
|
||||
import org.keycloak.sessions.RootAuthenticationSessionModel;
|
||||
import org.keycloak.services.util.UserSessionUtil;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
import org.keycloak.util.TokenUtil;
|
||||
import org.keycloak.utils.MediaType;
|
||||
|
@ -145,15 +139,15 @@ public class UserInfoEndpoint {
|
|||
authorization(accessToken);
|
||||
|
||||
try {
|
||||
|
||||
|
||||
String contentType = headers.getHeaderString(HttpHeaders.CONTENT_TYPE);
|
||||
jakarta.ws.rs.core.MediaType mediaType = jakarta.ws.rs.core.MediaType.valueOf(contentType);
|
||||
|
||||
|
||||
if (jakarta.ws.rs.core.MediaType.APPLICATION_FORM_URLENCODED_TYPE.isCompatible(mediaType)) {
|
||||
MultivaluedMap<String, String> formParams = request.getDecodedFormParameters();
|
||||
checkAccessTokenDuplicated(formParams);
|
||||
accessToken = formParams.getFirst(OAuth2Constants.ACCESS_TOKEN);
|
||||
authorization(accessToken);
|
||||
authorization(accessToken);
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
// not application/x-www-form-urlencoded, ignore
|
||||
|
@ -229,7 +223,7 @@ public class UserInfoEndpoint {
|
|||
throw error.invalidToken("Client disabled");
|
||||
}
|
||||
|
||||
UserSessionModel userSession = findValidSession(token, event, clientModel);
|
||||
UserSessionModel userSession = UserSessionUtil.findValidSession(session, realm, token, event, clientModel);
|
||||
|
||||
UserModel userModel = userSession.getUser();
|
||||
if (userModel == null) {
|
||||
|
@ -350,73 +344,6 @@ public class UserInfoEndpoint {
|
|||
return encryptedToken;
|
||||
}
|
||||
|
||||
private UserSessionModel createTransientSessionForClient(AccessToken token, ClientModel client) {
|
||||
// create a transient session
|
||||
UserModel user = TokenManager.lookupUserFromStatelessToken(session, realm, token);
|
||||
if (user == null) {
|
||||
throw error.invalidToken("User not found");
|
||||
}
|
||||
UserSessionModel userSession = new UserSessionManager(session).createUserSession(KeycloakModelUtils.generateId(), realm, user, user.getUsername(), clientConnection.getRemoteAddr(),
|
||||
ServiceAccountConstants.CLIENT_AUTH, false, null, null, UserSessionModel.SessionPersistenceState.TRANSIENT);
|
||||
// attach an auth session for the client
|
||||
RootAuthenticationSessionModel rootAuthSession = session.authenticationSessions().createRootAuthenticationSession(realm);
|
||||
AuthenticationSessionModel authSession = rootAuthSession.createAuthenticationSession(client);
|
||||
authSession.setAuthenticatedUser(userSession.getUser());
|
||||
authSession.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
|
||||
authSession.setClientNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(session.getContext().getUri().getBaseUri(), realm.getName()));
|
||||
AuthenticationManager.setClientScopesInSession(authSession);
|
||||
TokenManager.attachAuthenticationSession(session, userSession, authSession);
|
||||
return userSession;
|
||||
}
|
||||
|
||||
private UserSessionModel findValidSession(AccessToken token, EventBuilder event, ClientModel client) {
|
||||
if (token.getSessionState() == null) {
|
||||
return createTransientSessionForClient(token, client);
|
||||
}
|
||||
|
||||
UserSessionModel userSession = new UserSessionCrossDCManager(session).getUserSessionWithClient(realm, token.getSessionState(), false, client.getId());
|
||||
UserSessionModel offlineUserSession = null;
|
||||
if (AuthenticationManager.isSessionValid(realm, userSession)) {
|
||||
checkTokenIssuedAt(token, userSession, event, client);
|
||||
event.session(userSession);
|
||||
return userSession;
|
||||
} else {
|
||||
offlineUserSession = new UserSessionCrossDCManager(session).getUserSessionWithClient(realm, token.getSessionState(), true, client.getId());
|
||||
if (AuthenticationManager.isOfflineSessionValid(realm, offlineUserSession)) {
|
||||
checkTokenIssuedAt(token, offlineUserSession, event, client);
|
||||
event.session(offlineUserSession);
|
||||
return offlineUserSession;
|
||||
}
|
||||
}
|
||||
|
||||
if (userSession == null && offlineUserSession == null) {
|
||||
event.error(Errors.USER_SESSION_NOT_FOUND);
|
||||
throw error.invalidToken("User session not found or doesn't have client attached on it");
|
||||
}
|
||||
|
||||
if (userSession != null) {
|
||||
event.session(userSession);
|
||||
} else {
|
||||
event.session(offlineUserSession);
|
||||
}
|
||||
|
||||
event.error(Errors.SESSION_EXPIRED);
|
||||
throw error.invalidToken("Session expired");
|
||||
}
|
||||
|
||||
private void checkTokenIssuedAt(AccessToken token, UserSessionModel userSession, EventBuilder event, ClientModel client) {
|
||||
if (token.isIssuedBeforeSessionStart(userSession.getStarted())) {
|
||||
event.error(Errors.INVALID_TOKEN);
|
||||
throw error.invalidToken("Stale token");
|
||||
}
|
||||
|
||||
AuthenticatedClientSessionModel clientSession = userSession.getAuthenticatedClientSessionByClient(client.getId());
|
||||
if (token.isIssuedBeforeSessionStart(clientSession.getStarted())) {
|
||||
event.error(Errors.INVALID_TOKEN);
|
||||
throw error.invalidToken("Stale token");
|
||||
}
|
||||
}
|
||||
|
||||
private void checkAccessTokenDuplicated(MultivaluedMap<String, String> formParams) {
|
||||
// If access_token is not provided, error is thrown in issueUserInfo().
|
||||
// Only checks duplication of access token parameter in this function.
|
||||
|
|
|
@ -106,6 +106,17 @@ public abstract class AbstractOIDCProtocolMapper implements ProtocolMapper {
|
|||
return accessTokenResponse;
|
||||
}
|
||||
|
||||
public AccessToken transformIntrospectionToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
||||
UserSessionModel userSession, ClientSessionContext clientSessionCtx) {
|
||||
|
||||
if (!OIDCAttributeMapperHelper.includeInIntrospection(mappingModel)){
|
||||
return token;
|
||||
}
|
||||
|
||||
setClaim(token, mappingModel, userSession, session, clientSessionCtx);
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Intended to be overridden in {@link ProtocolMapper} implementations to add claims to an token.
|
||||
* @param token
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.keycloak.provider.ProviderConfigProperty;
|
|||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.IDToken;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -22,7 +23,7 @@ import java.util.List;
|
|||
*
|
||||
* @author <a href="mailto:martin.hardselius@gmail.com">Martin Hardselius</a>
|
||||
*/
|
||||
public abstract class AbstractPairwiseSubMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper {
|
||||
public abstract class AbstractPairwiseSubMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper, TokenIntrospectionTokenMapper {
|
||||
public static final String PROVIDER_ID_SUFFIX = "-pairwise-sub-mapper";
|
||||
|
||||
public abstract String getIdPrefix();
|
||||
|
@ -75,6 +76,12 @@ public abstract class AbstractPairwiseSubMapper extends AbstractOIDCProtocolMapp
|
|||
return token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessToken transformIntrospectionToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientSessionContext clientSessionCtx) {
|
||||
setAccessTokenSubject(token, generateSub(mappingModel, getSectorIdentifier(clientSessionCtx.getClientSession().getClient(), mappingModel), userSession.getUser().getId()));
|
||||
return token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessToken transformUserInfoToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientSessionContext clientSessionCtx) {
|
||||
setUserInfoTokenSubject(token, generateSub(mappingModel, getSectorIdentifier(clientSessionCtx.getClientSession().getClient(), mappingModel), userSession.getUser().getId()));
|
||||
|
|
|
@ -38,7 +38,7 @@ import java.util.stream.Collectors;
|
|||
*
|
||||
* @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
|
||||
*/
|
||||
abstract class AbstractUserRoleMappingMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper {
|
||||
abstract class AbstractUserRoleMappingMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper, TokenIntrospectionTokenMapper {
|
||||
|
||||
@Override
|
||||
public int getPriority() {
|
||||
|
|
|
@ -42,7 +42,7 @@ import org.keycloak.services.managers.AuthenticationManager;
|
|||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class AcrProtocolMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, EnvironmentDependentProviderFactory {
|
||||
public class AcrProtocolMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, TokenIntrospectionTokenMapper, EnvironmentDependentProviderFactory {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(AcrProtocolMapper.class);
|
||||
|
||||
|
@ -87,7 +87,7 @@ public class AcrProtocolMapper extends AbstractOIDCProtocolMapper implements OID
|
|||
token.setAcr(acr);
|
||||
}
|
||||
|
||||
public static ProtocolMapperModel create(String name, boolean accessToken, boolean idToken) {
|
||||
public static ProtocolMapperModel create(String name, boolean accessToken, boolean idToken, boolean introspectionEndpoint) {
|
||||
ProtocolMapperModel mapper = new ProtocolMapperModel();
|
||||
mapper.setName(name);
|
||||
mapper.setProtocolMapper(PROVIDER_ID);
|
||||
|
@ -95,6 +95,7 @@ public class AcrProtocolMapper extends AbstractOIDCProtocolMapper implements OID
|
|||
Map<String, String> config = new HashMap<>();
|
||||
if (accessToken) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true");
|
||||
if (idToken) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true");
|
||||
if (introspectionEndpoint) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_INTROSPECTION, "true");
|
||||
mapper.setConfig(config);
|
||||
return mapper;
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ import java.util.Map;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class AddressMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper {
|
||||
public class AddressMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper, TokenIntrospectionTokenMapper {
|
||||
|
||||
private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||
|
||||
|
@ -69,10 +69,10 @@ public class AddressMapper extends AbstractOIDCProtocolMapper implements OIDCAcc
|
|||
public static final String PROVIDER_ID = "oidc-address-mapper";
|
||||
|
||||
public static ProtocolMapperModel createAddressMapper() {
|
||||
return createAddressMapper(true, true, true);
|
||||
return createAddressMapper(true, true, true, true);
|
||||
}
|
||||
|
||||
public static ProtocolMapperModel createAddressMapper(boolean idToken, boolean accessToken, boolean userInfo) {
|
||||
public static ProtocolMapperModel createAddressMapper(boolean idToken, boolean accessToken, boolean userInfo, boolean introspectionEndpoint) {
|
||||
Map<String, String> config;
|
||||
ProtocolMapperModel address = new ProtocolMapperModel();
|
||||
address.setName("address");
|
||||
|
@ -82,6 +82,7 @@ public class AddressMapper extends AbstractOIDCProtocolMapper implements OIDCAcc
|
|||
config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, Boolean.toString(accessToken));
|
||||
config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, Boolean.toString(idToken));
|
||||
config.put(OIDCAttributeMapperHelper.INCLUDE_IN_USERINFO, Boolean.toString(userInfo));
|
||||
config.put(OIDCAttributeMapperHelper.INCLUDE_IN_INTROSPECTION, Boolean.toString(introspectionEndpoint));
|
||||
|
||||
config.put(getModelPropertyName(STREET), STREET);
|
||||
config.put(getModelPropertyName(AddressClaimSet.LOCALITY), AddressClaimSet.LOCALITY);
|
||||
|
|
|
@ -19,7 +19,9 @@ package org.keycloak.protocol.oidc.mappers;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.keycloak.models.ClientModel;
|
||||
|
@ -32,18 +34,24 @@ import org.keycloak.protocol.oidc.utils.WebOriginsUtils;
|
|||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
|
||||
import static org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN;
|
||||
import static org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper.INCLUDE_IN_INTROSPECTION;
|
||||
|
||||
/**
|
||||
* Protocol mapper to add allowed web origins to the access token to the 'allowed-origins' claim
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class AllowedWebOriginsProtocolMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper {
|
||||
public class AllowedWebOriginsProtocolMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, TokenIntrospectionTokenMapper {
|
||||
|
||||
private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||
|
||||
|
||||
public static final String PROVIDER_ID = "oidc-allowed-origins-mapper";
|
||||
|
||||
static {
|
||||
OIDCAttributeMapperHelper.addIncludeInTokensConfig(configProperties, AllowedWebOriginsProtocolMapper.class);
|
||||
}
|
||||
|
||||
public List<ProviderConfigProperty> getConfigProperties() {
|
||||
return configProperties;
|
||||
|
@ -72,23 +80,72 @@ public class AllowedWebOriginsProtocolMapper extends AbstractOIDCProtocolMapper
|
|||
@Override
|
||||
public AccessToken transformAccessToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
||||
UserSessionModel userSession, ClientSessionContext clientSessionCtx) {
|
||||
|
||||
if (!includeInAccessToken(mappingModel)){
|
||||
return token;
|
||||
}
|
||||
setWebOrigin(token, session, clientSessionCtx);
|
||||
return token;
|
||||
}
|
||||
|
||||
private boolean includeInAccessToken(ProtocolMapperModel mappingModel) {
|
||||
String includeInAccessToken = mappingModel.getConfig().get(INCLUDE_IN_ACCESS_TOKEN);
|
||||
|
||||
// Backwards compatibility
|
||||
if (includeInAccessToken == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return "true".equals(includeInAccessToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessToken transformIntrospectionToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
||||
UserSessionModel userSession, ClientSessionContext clientSessionCtx) {
|
||||
if (!includeInIntrospection(mappingModel)) {
|
||||
return token;
|
||||
}
|
||||
setWebOrigin(token, session, clientSessionCtx);
|
||||
return token;
|
||||
}
|
||||
|
||||
private boolean includeInIntrospection(ProtocolMapperModel mappingModel) {
|
||||
String includeInIntrospection = mappingModel.getConfig().get(INCLUDE_IN_INTROSPECTION);
|
||||
|
||||
// Backwards compatibility
|
||||
if (includeInIntrospection == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return "true".equals(includeInIntrospection);
|
||||
}
|
||||
|
||||
private void setWebOrigin(AccessToken token, KeycloakSession session, ClientSessionContext clientSessionCtx) {
|
||||
ClientModel client = clientSessionCtx.getClientSession().getClient();
|
||||
|
||||
Set<String> allowedOrigins = client.getWebOrigins();
|
||||
if (allowedOrigins != null && !allowedOrigins.isEmpty()) {
|
||||
token.setAllowedOrigins(WebOriginsUtils.resolveValidWebOrigins(session, client));
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
|
||||
public static ProtocolMapperModel createClaimMapper(String name) {
|
||||
public static ProtocolMapperModel createClaimMapper(String name, boolean accessToken, boolean introspectionEndpoint) {
|
||||
ProtocolMapperModel mapper = new ProtocolMapperModel();
|
||||
mapper.setName(name);
|
||||
mapper.setProtocolMapper(PROVIDER_ID);
|
||||
mapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
|
||||
mapper.setConfig(Collections.emptyMap());
|
||||
Map<String, String> config = new HashMap<>();
|
||||
if (accessToken) {
|
||||
config.put(INCLUDE_IN_ACCESS_TOKEN, "true");
|
||||
} else {
|
||||
config.put(INCLUDE_IN_ACCESS_TOKEN, "false");
|
||||
}
|
||||
if (introspectionEndpoint) {
|
||||
config.put(INCLUDE_IN_INTROSPECTION, "true");
|
||||
} else {
|
||||
config.put(INCLUDE_IN_INTROSPECTION, "false");
|
||||
}
|
||||
mapper.setConfig(config);
|
||||
return mapper;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ import org.keycloak.representations.IDToken;
|
|||
/**
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class AudienceProtocolMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper {
|
||||
public class AudienceProtocolMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, TokenIntrospectionTokenMapper {
|
||||
|
||||
private static final List<ProviderConfigProperty> configProperties = new ArrayList<>();
|
||||
|
||||
|
@ -115,7 +115,7 @@ public class AudienceProtocolMapper extends AbstractOIDCProtocolMapper implement
|
|||
public static ProtocolMapperModel createClaimMapper(String name,
|
||||
String includedClientAudience,
|
||||
String includedCustomAudience,
|
||||
boolean accessToken, boolean idToken) {
|
||||
boolean accessToken, boolean idToken, boolean introspectionEndpoint) {
|
||||
ProtocolMapperModel mapper = new ProtocolMapperModel();
|
||||
mapper.setName(name);
|
||||
mapper.setProtocolMapper(PROVIDER_ID);
|
||||
|
@ -131,6 +131,7 @@ public class AudienceProtocolMapper extends AbstractOIDCProtocolMapper implement
|
|||
|
||||
if (accessToken) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true");
|
||||
if (idToken) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true");
|
||||
if (introspectionEndpoint) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_INTROSPECTION, "true");
|
||||
mapper.setConfig(config);
|
||||
return mapper;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.keycloak.protocol.oidc.mappers;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -32,16 +33,21 @@ import org.keycloak.provider.ProviderConfigProperty;
|
|||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.utils.RoleResolveUtil;
|
||||
|
||||
import static org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN;
|
||||
import static org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper.INCLUDE_IN_INTROSPECTION;
|
||||
|
||||
/**
|
||||
* Protocol mapper, which adds all client_ids of "allowed" clients to the audience field of the token. Allowed client means the client
|
||||
* for which user has at least one client role
|
||||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class AudienceResolveProtocolMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper {
|
||||
public class AudienceResolveProtocolMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, TokenIntrospectionTokenMapper {
|
||||
|
||||
private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||
|
||||
static {
|
||||
OIDCAttributeMapperHelper.addIncludeInTokensConfig(configProperties, AudienceResolveProtocolMapper.class);
|
||||
}
|
||||
|
||||
public static final String PROVIDER_ID = "oidc-audience-resolve-mapper";
|
||||
|
||||
|
@ -79,6 +85,46 @@ public class AudienceResolveProtocolMapper extends AbstractOIDCProtocolMapper im
|
|||
@Override
|
||||
public AccessToken transformAccessToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
||||
UserSessionModel userSession, ClientSessionContext clientSessionCtx) {
|
||||
if (!includeInAccessToken(mappingModel)){
|
||||
return token;
|
||||
}
|
||||
setAudience(token, clientSessionCtx, session);
|
||||
return token;
|
||||
}
|
||||
|
||||
private boolean includeInAccessToken(ProtocolMapperModel mappingModel) {
|
||||
String includeInAccessToken = mappingModel.getConfig().get(INCLUDE_IN_ACCESS_TOKEN);
|
||||
|
||||
// Backwards compatibility
|
||||
if (includeInAccessToken == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return "true".equals(includeInAccessToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessToken transformIntrospectionToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
||||
UserSessionModel userSession, ClientSessionContext clientSessionCtx) {
|
||||
if (!includeInIntrospection(mappingModel)) {
|
||||
return token;
|
||||
}
|
||||
setAudience(token, clientSessionCtx, session);
|
||||
return token;
|
||||
}
|
||||
|
||||
private boolean includeInIntrospection(ProtocolMapperModel mappingModel) {
|
||||
String includeInIntrospection = mappingModel.getConfig().get(INCLUDE_IN_INTROSPECTION);
|
||||
|
||||
// Backwards compatibility
|
||||
if (includeInIntrospection == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return "true".equals(includeInIntrospection);
|
||||
}
|
||||
|
||||
private void setAudience(AccessToken token, ClientSessionContext clientSessionCtx, KeycloakSession session) {
|
||||
String clientId = clientSessionCtx.getClientSession().getClient().getClientId();
|
||||
|
||||
for (Map.Entry<String, AccessToken.Access> entry : RoleResolveUtil.getAllResolvedClientRoles(session, clientSessionCtx).entrySet()) {
|
||||
|
@ -92,16 +138,25 @@ public class AudienceResolveProtocolMapper extends AbstractOIDCProtocolMapper im
|
|||
token.addAudience(entry.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
public static ProtocolMapperModel createClaimMapper(String name) {
|
||||
public static ProtocolMapperModel createClaimMapper(String name, boolean accessToken, boolean introspectionEndpoint) {
|
||||
ProtocolMapperModel mapper = new ProtocolMapperModel();
|
||||
mapper.setName(name);
|
||||
mapper.setProtocolMapper(PROVIDER_ID);
|
||||
mapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
|
||||
mapper.setConfig(Collections.emptyMap());
|
||||
Map<String, String> config = new HashMap<>();
|
||||
if (accessToken) {
|
||||
config.put(INCLUDE_IN_ACCESS_TOKEN, "true");
|
||||
} else {
|
||||
config.put(INCLUDE_IN_ACCESS_TOKEN, "false");
|
||||
}
|
||||
if (introspectionEndpoint) {
|
||||
config.put(INCLUDE_IN_INTROSPECTION, "true");
|
||||
} else {
|
||||
config.put(INCLUDE_IN_INTROSPECTION, "false");
|
||||
}
|
||||
mapper.setConfig(config);
|
||||
return mapper;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,16 +110,16 @@ public class ClaimsParameterTokenMapper extends AbstractOIDCProtocolMapper imple
|
|||
fullNameMapper.setClaim(token, mappingModel, userSession);
|
||||
} else if (i.equals(IDToken.GIVEN_NAME)) {
|
||||
UserAttributeMapper userPropertyMapper = new UserAttributeMapper();
|
||||
userPropertyMapper.setClaim(token, UserAttributeMapper.createClaimMapper("requested firstName", "firstName", IDToken.GIVEN_NAME, "String", false, true), userSession);
|
||||
userPropertyMapper.setClaim(token, UserAttributeMapper.createClaimMapper("requested firstName", "firstName", IDToken.GIVEN_NAME, "String", false, true, false), userSession);
|
||||
} else if (i.equals(IDToken.FAMILY_NAME)) {
|
||||
UserAttributeMapper userPropertyMapper = new UserAttributeMapper();
|
||||
userPropertyMapper.setClaim(token, UserAttributeMapper.createClaimMapper("requested lastName", "lastName", IDToken.FAMILY_NAME, "String", false, true), userSession);
|
||||
userPropertyMapper.setClaim(token, UserAttributeMapper.createClaimMapper("requested lastName", "lastName", IDToken.FAMILY_NAME, "String", false, true, false), userSession);
|
||||
} else if (i.equals(IDToken.PREFERRED_USERNAME)) {
|
||||
UserAttributeMapper userPropertyMapper = new UserAttributeMapper();
|
||||
userPropertyMapper.setClaim(token, UserAttributeMapper.createClaimMapper("requested username", "username", IDToken.PREFERRED_USERNAME, "String", false, true), userSession);
|
||||
userPropertyMapper.setClaim(token, UserAttributeMapper.createClaimMapper("requested username", "username", IDToken.PREFERRED_USERNAME, "String", false, true, false), userSession);
|
||||
} else if (i.equals(IDToken.EMAIL)) {
|
||||
UserAttributeMapper userPropertyMapper = new UserAttributeMapper();
|
||||
userPropertyMapper.setClaim(token, UserAttributeMapper.createClaimMapper("requested email", "email", IDToken.EMAIL, "String", false, true), userSession);
|
||||
userPropertyMapper.setClaim(token, UserAttributeMapper.createClaimMapper("requested email", "email", IDToken.EMAIL, "String", false, true, false), userSession);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -123,7 +123,7 @@ public class ClaimsParameterWithValueIdTokenMapper extends AbstractOIDCProtocolM
|
|||
}
|
||||
|
||||
HardcodedClaim hardcodedClaimMapper = new HardcodedClaim();
|
||||
hardcodedClaimMapper.setClaim(token, HardcodedClaim.create("hard", claimName, claim, "String", false, true), userSession);
|
||||
hardcodedClaimMapper.setClaim(token, HardcodedClaim.create("hard", claimName, claim, "String", false, true, false), userSession);
|
||||
}
|
||||
|
||||
public static ProtocolMapperModel createMapper(String name, String attributeValue, boolean idToken) {
|
||||
|
|
|
@ -37,7 +37,7 @@ import java.util.Optional;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class FullNameMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper {
|
||||
public class FullNameMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper, TokenIntrospectionTokenMapper {
|
||||
|
||||
private static final List<ProviderConfigProperty> configProperties = new ArrayList<>();
|
||||
|
||||
|
@ -83,7 +83,7 @@ public class FullNameMapper extends AbstractOIDCProtocolMapper implements OIDCAc
|
|||
}
|
||||
}
|
||||
|
||||
public static ProtocolMapperModel create(String name, boolean accessToken, boolean idToken, boolean userInfo) {
|
||||
public static ProtocolMapperModel create(String name, boolean accessToken, boolean idToken, boolean userInfo, boolean introspectionEndpoint) {
|
||||
ProtocolMapperModel mapper = new ProtocolMapperModel();
|
||||
mapper.setName(name);
|
||||
mapper.setProtocolMapper(PROVIDER_ID);
|
||||
|
@ -92,6 +92,7 @@ public class FullNameMapper extends AbstractOIDCProtocolMapper implements OIDCAc
|
|||
if (accessToken) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true");
|
||||
if (idToken) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true");
|
||||
if (userInfo) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_USERINFO, "true");
|
||||
if (introspectionEndpoint) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_INTROSPECTION, "true");
|
||||
mapper.setConfig(config);
|
||||
return mapper;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ import java.util.stream.Collectors;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class GroupMembershipMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper {
|
||||
public class GroupMembershipMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper, TokenIntrospectionTokenMapper {
|
||||
|
||||
private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||
|
||||
|
@ -105,9 +105,9 @@ public class GroupMembershipMapper extends AbstractOIDCProtocolMapper implements
|
|||
}
|
||||
|
||||
public static ProtocolMapperModel create(String name,
|
||||
String tokenClaimName,
|
||||
boolean consentRequired, String consentText,
|
||||
boolean accessToken, boolean idToken) {
|
||||
String tokenClaimName,
|
||||
boolean consentRequired, String consentText,
|
||||
boolean accessToken, boolean idToken, boolean introspectionEndpoint) {
|
||||
ProtocolMapperModel mapper = new ProtocolMapperModel();
|
||||
mapper.setName(name);
|
||||
mapper.setProtocolMapper(PROVIDER_ID);
|
||||
|
@ -116,8 +116,9 @@ public class GroupMembershipMapper extends AbstractOIDCProtocolMapper implements
|
|||
config.put(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, tokenClaimName);
|
||||
if (accessToken) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true");
|
||||
if (idToken) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true");
|
||||
if (introspectionEndpoint) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_INTROSPECTION, "true");
|
||||
mapper.setConfig(config);
|
||||
|
||||
|
||||
return mapper;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ import java.util.Map;
|
|||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class HardcodedClaim extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper,
|
||||
OIDCAccessTokenResponseMapper {
|
||||
OIDCAccessTokenResponseMapper, TokenIntrospectionTokenMapper {
|
||||
|
||||
private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||
|
||||
|
@ -94,7 +94,7 @@ public class HardcodedClaim extends AbstractOIDCProtocolMapper implements OIDCAc
|
|||
|
||||
@Override
|
||||
protected void setClaim(AccessTokenResponse accessTokenResponse, ProtocolMapperModel mappingModel, UserSessionModel userSession,
|
||||
KeycloakSession keycloakSession, ClientSessionContext clientSessionCtx) {
|
||||
KeycloakSession keycloakSession, ClientSessionContext clientSessionCtx) {
|
||||
|
||||
String attributeValue = mappingModel.getConfig().get(CLAIM_VALUE);
|
||||
if (attributeValue == null) return;
|
||||
|
@ -102,9 +102,9 @@ public class HardcodedClaim extends AbstractOIDCProtocolMapper implements OIDCAc
|
|||
}
|
||||
|
||||
public static ProtocolMapperModel create(String name,
|
||||
String hardcodedName,
|
||||
String hardcodedValue, String claimType,
|
||||
boolean accessToken, boolean idToken) {
|
||||
String hardcodedName,
|
||||
String hardcodedValue, String claimType,
|
||||
boolean accessToken, boolean idToken, boolean introspectionEndpoint) {
|
||||
ProtocolMapperModel mapper = new ProtocolMapperModel();
|
||||
mapper.setName(name);
|
||||
mapper.setProtocolMapper(PROVIDER_ID);
|
||||
|
@ -115,6 +115,7 @@ public class HardcodedClaim extends AbstractOIDCProtocolMapper implements OIDCAc
|
|||
config.put(OIDCAttributeMapperHelper.JSON_TYPE, claimType);
|
||||
if (accessToken) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true");
|
||||
if (idToken) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true");
|
||||
if (introspectionEndpoint) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_INTROSPECTION, "true");
|
||||
mapper.setConfig(config);
|
||||
return mapper;
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ import java.util.Map;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class HardcodedRole extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, UserInfoTokenMapper {
|
||||
public class HardcodedRole extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, UserInfoTokenMapper, TokenIntrospectionTokenMapper {
|
||||
|
||||
private static final List<ProviderConfigProperty> configProperties = new ArrayList<>();
|
||||
|
||||
|
@ -104,6 +104,14 @@ public class HardcodedRole extends AbstractOIDCProtocolMapper implements OIDCAcc
|
|||
return token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessToken transformIntrospectionToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
||||
UserSessionModel userSession, ClientSessionContext clientSessionCtx) {
|
||||
// the mapper is always executed and then other role mappers decide if the claims are really set to the token
|
||||
setClaim(token, mappingModel, userSession, session, clientSessionCtx);
|
||||
return token;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setClaim(IDToken token, ProtocolMapperModel mappingModel, UserSessionModel userSession, KeycloakSession session,
|
||||
ClientSessionContext clientSessionCtx) {
|
||||
|
|
|
@ -31,10 +31,17 @@ import org.keycloak.representations.IDToken;
|
|||
import org.keycloak.services.ServicesLogger;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
|
@ -60,6 +67,10 @@ public class OIDCAttributeMapperHelper {
|
|||
public static final String INCLUDE_IN_USERINFO_LABEL = "includeInUserInfo.label";
|
||||
public static final String INCLUDE_IN_USERINFO_HELP_TEXT = "includeInUserInfo.tooltip";
|
||||
|
||||
public static final String INCLUDE_IN_INTROSPECTION = "introspection.token.claim";
|
||||
public static final String INCLUDE_IN_INTROSPECTION_LABEL = "includeInIntrospection.label";
|
||||
public static final String INCLUDE_IN_INTROSPECTION_HELP_TEXT = "includeInIntrospection.tooltip";
|
||||
|
||||
private static final Logger logger = Logger.getLogger(OIDCAttributeMapperHelper.class);
|
||||
|
||||
/**
|
||||
|
@ -230,7 +241,7 @@ public class OIDCAttributeMapperHelper {
|
|||
if (attributeValue instanceof String) return Boolean.valueOf((String) attributeValue);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private static JsonNode getJsonNode(Object attributeValue) {
|
||||
if (attributeValue instanceof JsonNode){
|
||||
return (JsonNode) attributeValue;
|
||||
|
@ -259,7 +270,7 @@ public class OIDCAttributeMapperHelper {
|
|||
}
|
||||
|
||||
private static <T> void mapClaim(T token, ProtocolMapperModel mappingModel, Object attributeValue,
|
||||
Map<String, PropertySetter<T>> setters, Map<String, Object> jsonObject) {
|
||||
Map<String, PropertySetter<T>> setters, Map<String, Object> jsonObject) {
|
||||
attributeValue = mapAttributeValue(mappingModel, attributeValue);
|
||||
if (attributeValue == null) {
|
||||
return;
|
||||
|
@ -317,16 +328,16 @@ public class OIDCAttributeMapperHelper {
|
|||
public static ProtocolMapperModel createClaimMapper(String name,
|
||||
String userAttribute,
|
||||
String tokenClaimName, String claimType,
|
||||
boolean accessToken, boolean idToken,
|
||||
boolean accessToken, boolean idToken, boolean introspectionEndpoint,
|
||||
String mapperId) {
|
||||
return createClaimMapper(name, userAttribute,tokenClaimName, claimType, accessToken, idToken, true, mapperId);
|
||||
return createClaimMapper(name, userAttribute, tokenClaimName, claimType, accessToken, idToken, true, introspectionEndpoint, mapperId);
|
||||
}
|
||||
|
||||
public static ProtocolMapperModel createClaimMapper(String name,
|
||||
String userAttribute,
|
||||
String tokenClaimName, String claimType,
|
||||
boolean accessToken, boolean idToken, boolean userinfo,
|
||||
String mapperId) {
|
||||
String userAttribute,
|
||||
String tokenClaimName, String claimType,
|
||||
boolean accessToken, boolean idToken, boolean userinfo, boolean introspectionEndpoint,
|
||||
String mapperId) {
|
||||
ProtocolMapperModel mapper = new ProtocolMapperModel();
|
||||
mapper.setName(name);
|
||||
mapper.setProtocolMapper(mapperId);
|
||||
|
@ -338,6 +349,7 @@ public class OIDCAttributeMapperHelper {
|
|||
if (accessToken) config.put(INCLUDE_IN_ACCESS_TOKEN, "true");
|
||||
if (idToken) config.put(INCLUDE_IN_ID_TOKEN, "true");
|
||||
if (userinfo) config.put(INCLUDE_IN_USERINFO, "true");
|
||||
if (introspectionEndpoint) config.put(INCLUDE_IN_INTROSPECTION, "true");
|
||||
mapper.setConfig(config);
|
||||
return mapper;
|
||||
}
|
||||
|
@ -369,6 +381,17 @@ public class OIDCAttributeMapperHelper {
|
|||
return "true".equals(includeInUserInfo);
|
||||
}
|
||||
|
||||
public static boolean includeInIntrospection(ProtocolMapperModel mappingModel) {
|
||||
String includeInIntrospection = mappingModel.getConfig().get(INCLUDE_IN_INTROSPECTION);
|
||||
|
||||
// Backwards compatibility
|
||||
if (includeInIntrospection == null && includeInAccessToken(mappingModel)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return "true".equals(includeInIntrospection);
|
||||
}
|
||||
|
||||
public static void addAttributeConfig(List<ProviderConfigProperty> configProperties, Class<? extends ProtocolMapper> protocolMapperClass) {
|
||||
addTokenClaimNameConfig(configProperties);
|
||||
addJsonTypeConfig(configProperties);
|
||||
|
@ -441,5 +464,15 @@ public class OIDCAttributeMapperHelper {
|
|||
property.setHelpText(INCLUDE_IN_ACCESS_TOKEN_RESPONSE_HELP_TEXT);
|
||||
configProperties.add(property);
|
||||
}
|
||||
|
||||
if (TokenIntrospectionTokenMapper.class.isAssignableFrom(protocolMapperClass)) {
|
||||
ProviderConfigProperty property = new ProviderConfigProperty();
|
||||
property.setName(INCLUDE_IN_INTROSPECTION);
|
||||
property.setLabel(INCLUDE_IN_INTROSPECTION_LABEL);
|
||||
property.setType(ProviderConfigProperty.BOOLEAN_TYPE);
|
||||
property.setDefaultValue("true");
|
||||
property.setHelpText(INCLUDE_IN_INTROSPECTION_HELP_TEXT);
|
||||
configProperties.add(property);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ import java.util.Map;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class RoleNameMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, UserInfoTokenMapper {
|
||||
public class RoleNameMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, UserInfoTokenMapper, TokenIntrospectionTokenMapper {
|
||||
|
||||
private static final List<ProviderConfigProperty> configProperties = new ArrayList<>();
|
||||
|
||||
|
@ -111,6 +111,14 @@ public class RoleNameMapper extends AbstractOIDCProtocolMapper implements OIDCAc
|
|||
return token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessToken transformIntrospectionToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
||||
UserSessionModel userSession, ClientSessionContext clientSessionCtx) {
|
||||
// the mapper is always executed and then other role mappers decide if the claims are really set to the token
|
||||
setClaim(token, mappingModel, userSession, session, clientSessionCtx);
|
||||
return token;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setClaim(IDToken token, ProtocolMapperModel mappingModel, UserSessionModel userSession, KeycloakSession session,
|
||||
ClientSessionContext clientSessionCtx) {
|
||||
|
|
|
@ -46,7 +46,7 @@ import java.util.List;
|
|||
* @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
|
||||
*/
|
||||
public class ScriptBasedOIDCProtocolMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper,
|
||||
OIDCAccessTokenResponseMapper, EnvironmentDependentProviderFactory {
|
||||
OIDCAccessTokenResponseMapper, TokenIntrospectionTokenMapper, EnvironmentDependentProviderFactory {
|
||||
|
||||
public static final String PROVIDER_ID = "oidc-script-based-protocol-mapper";
|
||||
|
||||
|
@ -197,14 +197,14 @@ public class ScriptBasedOIDCProtocolMapper extends AbstractOIDCProtocolMapper im
|
|||
public static ProtocolMapperModel create(String name,
|
||||
String userAttribute,
|
||||
String tokenClaimName, String claimType,
|
||||
boolean accessToken, boolean idToken, String script, boolean multiValued) {
|
||||
boolean accessToken, boolean idToken, boolean introspectionEndpoint, String script, boolean multiValued) {
|
||||
ProtocolMapperModel mapper = OIDCAttributeMapperHelper.createClaimMapper(name, userAttribute,
|
||||
tokenClaimName, claimType,
|
||||
accessToken, idToken,
|
||||
accessToken, idToken, introspectionEndpoint,
|
||||
script);
|
||||
|
||||
mapper.getConfig().put(ProtocolMapperUtils.MULTIVALUED, String.valueOf(multiValued));
|
||||
|
||||
return mapper;
|
||||
return mapper;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package org.keycloak.protocol.oidc.mappers;
|
||||
|
||||
import org.keycloak.models.ClientSessionContext;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
|
||||
public interface TokenIntrospectionTokenMapper {
|
||||
AccessToken transformIntrospectionToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
|
||||
UserSessionModel userSession, ClientSessionContext clientSessionCtx);
|
||||
}
|
|
@ -37,7 +37,7 @@ import java.util.List;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class UserAttributeMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper {
|
||||
public class UserAttributeMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper, TokenIntrospectionTokenMapper {
|
||||
|
||||
private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||
|
||||
|
@ -106,19 +106,19 @@ public class UserAttributeMapper extends AbstractOIDCProtocolMapper implements O
|
|||
public static ProtocolMapperModel createClaimMapper(String name,
|
||||
String userAttribute,
|
||||
String tokenClaimName, String claimType,
|
||||
boolean accessToken, boolean idToken, boolean multivalued) {
|
||||
boolean accessToken, boolean idToken, boolean introspectionEndpoint, boolean multivalued) {
|
||||
return createClaimMapper(name, userAttribute, tokenClaimName, claimType,
|
||||
accessToken, idToken, multivalued, false);
|
||||
accessToken, idToken, introspectionEndpoint, multivalued, false);
|
||||
}
|
||||
|
||||
public static ProtocolMapperModel createClaimMapper(String name,
|
||||
String userAttribute,
|
||||
String tokenClaimName, String claimType,
|
||||
boolean accessToken, boolean idToken,
|
||||
boolean accessToken, boolean idToken, boolean introspectionEndpoint,
|
||||
boolean multivalued, boolean aggregateAttrs) {
|
||||
ProtocolMapperModel mapper = OIDCAttributeMapperHelper.createClaimMapper(name, userAttribute,
|
||||
tokenClaimName, claimType,
|
||||
accessToken, idToken,
|
||||
accessToken, idToken, introspectionEndpoint,
|
||||
PROVIDER_ID);
|
||||
|
||||
if (multivalued) {
|
||||
|
@ -134,8 +134,8 @@ public class UserAttributeMapper extends AbstractOIDCProtocolMapper implements O
|
|||
public static ProtocolMapperModel createClaimMapper(String name,
|
||||
String userAttribute,
|
||||
String tokenClaimName, String claimType,
|
||||
boolean accessToken, boolean idToken) {
|
||||
boolean accessToken, boolean idToken, boolean introspectionEndpoint) {
|
||||
return createClaimMapper(name, userAttribute, tokenClaimName, claimType,
|
||||
accessToken, idToken, false, false);
|
||||
accessToken, idToken, introspectionEndpoint, false, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -135,18 +135,18 @@ public class UserClientRoleMappingMapper extends AbstractUserRoleMappingMapper {
|
|||
public static ProtocolMapperModel create(String clientId, String clientRolePrefix,
|
||||
String name,
|
||||
String tokenClaimName,
|
||||
boolean accessToken, boolean idToken) {
|
||||
return create(clientId, clientRolePrefix, name, tokenClaimName, accessToken, idToken, false);
|
||||
boolean accessToken, boolean idToken, boolean introspectionEndpoint) {
|
||||
return create(clientId, clientRolePrefix, name, tokenClaimName, accessToken, idToken, introspectionEndpoint, false);
|
||||
|
||||
}
|
||||
|
||||
public static ProtocolMapperModel create(String clientId, String clientRolePrefix,
|
||||
String name,
|
||||
String tokenClaimName,
|
||||
boolean accessToken, boolean idToken, boolean multiValued) {
|
||||
boolean accessToken, boolean idToken, boolean introspectionEndpoint, boolean multiValued) {
|
||||
ProtocolMapperModel mapper = OIDCAttributeMapperHelper.createClaimMapper(name, "foo",
|
||||
tokenClaimName, "String",
|
||||
accessToken, idToken, false,
|
||||
accessToken, idToken, false, introspectionEndpoint,
|
||||
PROVIDER_ID);
|
||||
|
||||
mapper.getConfig().put(ProtocolMapperUtils.MULTIVALUED, String.valueOf(multiValued));
|
||||
|
|
|
@ -35,7 +35,7 @@ import java.util.List;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class UserPropertyMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper {
|
||||
public class UserPropertyMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper, TokenIntrospectionTokenMapper {
|
||||
private static final List<ProviderConfigProperty> configProperties = new ArrayList<ProviderConfigProperty>();
|
||||
|
||||
static {
|
||||
|
@ -89,10 +89,10 @@ public class UserPropertyMapper extends AbstractOIDCProtocolMapper implements OI
|
|||
public static ProtocolMapperModel createClaimMapper(String name,
|
||||
String userAttribute,
|
||||
String tokenClaimName, String claimType,
|
||||
boolean accessToken, boolean idToken) {
|
||||
boolean accessToken, boolean idToken, boolean introspectionEndpoint) {
|
||||
return OIDCAttributeMapperHelper.createClaimMapper(name, userAttribute,
|
||||
tokenClaimName, claimType,
|
||||
accessToken, idToken,
|
||||
accessToken, idToken, introspectionEndpoint,
|
||||
PROVIDER_ID);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,18 +100,18 @@ public class UserRealmRoleMappingMapper extends AbstractUserRoleMappingMapper {
|
|||
|
||||
public static ProtocolMapperModel create(String realmRolePrefix,
|
||||
String name,
|
||||
String tokenClaimName, boolean accessToken, boolean idToken) {
|
||||
String tokenClaimName, boolean accessToken, boolean idToken, boolean introspectionEndpoint) {
|
||||
|
||||
return create(realmRolePrefix, name, tokenClaimName, accessToken, idToken, false);
|
||||
return create(realmRolePrefix, name, tokenClaimName, accessToken, idToken, introspectionEndpoint, false);
|
||||
}
|
||||
|
||||
public static ProtocolMapperModel create(String realmRolePrefix,
|
||||
String name,
|
||||
String tokenClaimName, boolean accessToken, boolean idToken, boolean multiValued) {
|
||||
String tokenClaimName, boolean accessToken, boolean idToken, boolean introspectionEndpoint, boolean multiValued) {
|
||||
ProtocolMapperModel mapper = OIDCAttributeMapperHelper.createClaimMapper(name, "foo",
|
||||
tokenClaimName, "String",
|
||||
accessToken, idToken, false,
|
||||
PROVIDER_ID);
|
||||
tokenClaimName, "String",
|
||||
accessToken, idToken, false, introspectionEndpoint,
|
||||
PROVIDER_ID);
|
||||
|
||||
mapper.getConfig().put(ProtocolMapperUtils.MULTIVALUED, String.valueOf(multiValued));
|
||||
mapper.getConfig().put(ProtocolMapperUtils.USER_MODEL_REALM_ROLE_MAPPING_ROLE_PREFIX, realmRolePrefix);
|
||||
|
|
|
@ -38,7 +38,7 @@ import java.util.Map;
|
|||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class UserSessionNoteMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, OIDCAccessTokenResponseMapper, UserInfoTokenMapper {
|
||||
public class UserSessionNoteMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, OIDCAccessTokenResponseMapper, UserInfoTokenMapper, TokenIntrospectionTokenMapper {
|
||||
|
||||
private static final List<ProviderConfigProperty> configProperties = new ArrayList<>();
|
||||
|
||||
|
@ -90,7 +90,7 @@ public class UserSessionNoteMapper extends AbstractOIDCProtocolMapper implements
|
|||
|
||||
@Override
|
||||
protected void setClaim(AccessTokenResponse accessTokenResponse, ProtocolMapperModel mappingModel, UserSessionModel userSession,
|
||||
KeycloakSession keycloakSession, ClientSessionContext clientSessionCtx) {
|
||||
KeycloakSession keycloakSession, ClientSessionContext clientSessionCtx) {
|
||||
|
||||
String noteName = mappingModel.getConfig().get(ProtocolMapperUtils.USER_SESSION_NOTE);
|
||||
String noteValue = userSession.getNote(noteName);
|
||||
|
@ -101,14 +101,14 @@ public class UserSessionNoteMapper extends AbstractOIDCProtocolMapper implements
|
|||
public static ProtocolMapperModel createClaimMapper(String name,
|
||||
String userSessionNote,
|
||||
String tokenClaimName, String jsonType,
|
||||
boolean accessToken, boolean idToken) {
|
||||
return createClaimMapper(name, userSessionNote, tokenClaimName, jsonType, accessToken, idToken, false);
|
||||
boolean accessToken, boolean idToken, boolean introspectionEndpoint) {
|
||||
return createClaimMapper(name, userSessionNote, tokenClaimName, jsonType, accessToken, idToken, false, introspectionEndpoint);
|
||||
}
|
||||
|
||||
public static ProtocolMapperModel createClaimMapper(String name,
|
||||
String userSessionNote,
|
||||
String tokenClaimName, String jsonType,
|
||||
boolean accessToken, boolean idToken, boolean userInfo) {
|
||||
boolean accessToken, boolean idToken, boolean userInfo, boolean introspectionEndpoint) {
|
||||
ProtocolMapperModel mapper = new ProtocolMapperModel();
|
||||
mapper.setName(name);
|
||||
mapper.setProtocolMapper(PROVIDER_ID);
|
||||
|
@ -120,6 +120,7 @@ public class UserSessionNoteMapper extends AbstractOIDCProtocolMapper implements
|
|||
if (accessToken) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true");
|
||||
if (idToken) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true");
|
||||
if (userInfo) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_USERINFO, "true");
|
||||
if (introspectionEndpoint) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_INTROSPECTION, "true");
|
||||
mapper.setConfig(config);
|
||||
return mapper;
|
||||
}
|
||||
|
@ -135,7 +136,7 @@ public class UserSessionNoteMapper extends AbstractOIDCProtocolMapper implements
|
|||
userSessionNoteDescriptor.toString(),
|
||||
userSessionNoteDescriptor.getTokenClaim(),
|
||||
"String",
|
||||
true, true
|
||||
true, true, true
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -170,7 +170,7 @@ public class ClientManager {
|
|||
ProtocolMapperModel protocolMapper = UserSessionNoteMapper.createClaimMapper(ServiceAccountConstants.CLIENT_ID_PROTOCOL_MAPPER,
|
||||
ServiceAccountConstants.CLIENT_ID,
|
||||
ServiceAccountConstants.CLIENT_ID, "String",
|
||||
true, true);
|
||||
true, true, true);
|
||||
client.addProtocolMapper(protocolMapper);
|
||||
}
|
||||
|
||||
|
@ -180,7 +180,7 @@ public class ClientManager {
|
|||
ProtocolMapperModel protocolMapper = UserSessionNoteMapper.createClaimMapper(ServiceAccountConstants.CLIENT_HOST_PROTOCOL_MAPPER,
|
||||
ServiceAccountConstants.CLIENT_HOST,
|
||||
ServiceAccountConstants.CLIENT_HOST, "String",
|
||||
true, true);
|
||||
true, true, true);
|
||||
client.addProtocolMapper(protocolMapper);
|
||||
}
|
||||
|
||||
|
@ -189,7 +189,7 @@ public class ClientManager {
|
|||
ProtocolMapperModel protocolMapper = UserSessionNoteMapper.createClaimMapper(ServiceAccountConstants.CLIENT_ADDRESS_PROTOCOL_MAPPER,
|
||||
ServiceAccountConstants.CLIENT_ADDRESS,
|
||||
ServiceAccountConstants.CLIENT_ADDRESS, "String",
|
||||
true, true);
|
||||
true, true, true);
|
||||
client.addProtocolMapper(protocolMapper);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
package org.keycloak.services.util;
|
||||
|
||||
import org.keycloak.common.ClientConnection;
|
||||
import org.keycloak.common.constants.ServiceAccountConstants;
|
||||
import org.keycloak.events.Errors;
|
||||
import org.keycloak.events.EventBuilder;
|
||||
import org.keycloak.models.AuthenticatedClientSessionModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import org.keycloak.protocol.oidc.TokenManager;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.services.Urls;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
import org.keycloak.services.managers.UserSessionCrossDCManager;
|
||||
import org.keycloak.services.managers.UserSessionManager;
|
||||
import org.keycloak.sessions.AuthenticationSessionModel;
|
||||
import org.keycloak.sessions.RootAuthenticationSessionModel;
|
||||
import org.keycloak.utils.OAuth2Error;
|
||||
|
||||
public class UserSessionUtil {
|
||||
|
||||
public static UserSessionModel findValidSession(KeycloakSession session, RealmModel realm, AccessToken token, EventBuilder event, ClientModel client) {
|
||||
OAuth2Error error = new OAuth2Error().json(false).realm(realm);
|
||||
if (token.getSessionState() == null) {
|
||||
return createTransientSessionForClient(session, realm, token, client);
|
||||
}
|
||||
|
||||
UserSessionModel userSession = new UserSessionCrossDCManager(session).getUserSessionWithClient(realm, token.getSessionState(), false, client.getId());
|
||||
UserSessionModel offlineUserSession = null;
|
||||
if (AuthenticationManager.isSessionValid(realm, userSession)) {
|
||||
checkTokenIssuedAt(realm, token, userSession, event, client);
|
||||
event.session(userSession);
|
||||
return userSession;
|
||||
} else {
|
||||
offlineUserSession = new UserSessionCrossDCManager(session).getUserSessionWithClient(realm, token.getSessionState(), true, client.getId());
|
||||
if (AuthenticationManager.isOfflineSessionValid(realm, offlineUserSession)) {
|
||||
checkTokenIssuedAt(realm, token, offlineUserSession, event, client);
|
||||
event.session(offlineUserSession);
|
||||
return offlineUserSession;
|
||||
}
|
||||
}
|
||||
|
||||
if (userSession == null && offlineUserSession == null) {
|
||||
event.error(Errors.USER_SESSION_NOT_FOUND);
|
||||
throw error.invalidToken("User session not found or doesn't have client attached on it");
|
||||
}
|
||||
|
||||
if (userSession != null) {
|
||||
event.session(userSession);
|
||||
} else {
|
||||
event.session(offlineUserSession);
|
||||
}
|
||||
|
||||
event.error(Errors.SESSION_EXPIRED);
|
||||
throw error.invalidToken("Session expired");
|
||||
}
|
||||
|
||||
private static UserSessionModel createTransientSessionForClient(KeycloakSession session, RealmModel realm, AccessToken token, ClientModel client) {
|
||||
OAuth2Error error = new OAuth2Error().json(false).realm(realm);
|
||||
// create a transient session
|
||||
UserModel user = TokenManager.lookupUserFromStatelessToken(session, realm, token);
|
||||
if (user == null) {
|
||||
throw error.invalidToken("User not found");
|
||||
}
|
||||
ClientConnection clientConnection = session.getContext().getConnection();
|
||||
UserSessionModel userSession = new UserSessionManager(session).createUserSession(KeycloakModelUtils.generateId(), realm, user, user.getUsername(), clientConnection.getRemoteAddr(),
|
||||
ServiceAccountConstants.CLIENT_AUTH, false, null, null, UserSessionModel.SessionPersistenceState.TRANSIENT);
|
||||
// attach an auth session for the client
|
||||
RootAuthenticationSessionModel rootAuthSession = session.authenticationSessions().createRootAuthenticationSession(realm);
|
||||
AuthenticationSessionModel authSession = rootAuthSession.createAuthenticationSession(client);
|
||||
authSession.setAuthenticatedUser(userSession.getUser());
|
||||
authSession.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
|
||||
authSession.setClientNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(session.getContext().getUri().getBaseUri(), realm.getName()));
|
||||
AuthenticationManager.setClientScopesInSession(authSession);
|
||||
TokenManager.attachAuthenticationSession(session, userSession, authSession);
|
||||
return userSession;
|
||||
}
|
||||
|
||||
private static void checkTokenIssuedAt(RealmModel realm, AccessToken token, UserSessionModel userSession, EventBuilder event, ClientModel client) {
|
||||
OAuth2Error error = new OAuth2Error().json(false).realm(realm);
|
||||
if (token.isIssuedBeforeSessionStart(userSession.getStarted())) {
|
||||
event.error(Errors.INVALID_TOKEN);
|
||||
throw error.invalidToken("Stale token");
|
||||
}
|
||||
|
||||
AuthenticatedClientSessionModel clientSession = userSession.getAuthenticatedClientSessionByClient(client.getId());
|
||||
if (token.isIssuedBeforeSessionStart(clientSession.getStarted())) {
|
||||
event.error(Errors.INVALID_TOKEN);
|
||||
throw error.invalidToken("Stale token");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -817,7 +817,7 @@ public class TestingResourceProvider implements RealmResourceProvider {
|
|||
clientScopeModel.setIncludeInTokenScope(true);
|
||||
|
||||
// Add audience protocol mapper
|
||||
ProtocolMapperModel audienceMapper = AudienceProtocolMapper.createClaimMapper("Audience for " + clientId, clientId, null,true, false);
|
||||
ProtocolMapperModel audienceMapper = AudienceProtocolMapper.createClaimMapper("Audience for " + clientId, clientId, null,true, false, true );
|
||||
clientScopeModel.addProtocolMapper(audienceMapper);
|
||||
|
||||
return clientScopeModel.getId();
|
||||
|
|
|
@ -21,12 +21,12 @@ public class KcOidcBrokerSubMatchIntrospectionTest extends AbstractBrokerTest {
|
|||
@Override
|
||||
public List<ClientRepresentation> createConsumerClients() {
|
||||
List<ClientRepresentation> clients = new ArrayList<>(super.createConsumerClients());
|
||||
|
||||
|
||||
clients.add(ClientBuilder.create().clientId("consumer-client")
|
||||
.publicClient()
|
||||
.redirectUris(getConsumerRoot() + "/auth/realms/master/app/auth/*")
|
||||
.publicClient().build());
|
||||
|
||||
|
||||
return clients;
|
||||
}
|
||||
|
||||
|
@ -36,14 +36,14 @@ public class KcOidcBrokerSubMatchIntrospectionTest extends AbstractBrokerTest {
|
|||
List<ProtocolMapperRepresentation> mappers = new ArrayList<>();
|
||||
|
||||
ProtocolMapperRepresentation hardcodedClaim = createHardcodedClaim("sub-override", "sub", "overriden",
|
||||
"String", false, false);
|
||||
|
||||
"String", false, false, false);
|
||||
|
||||
hardcodedClaim.getConfig().put(OIDCAttributeMapperHelper.INCLUDE_IN_USERINFO, Boolean.TRUE.toString());
|
||||
|
||||
|
||||
mappers.add(hardcodedClaim);
|
||||
|
||||
|
||||
clients.get(0).setProtocolMappers(mappers);
|
||||
|
||||
|
||||
return clients;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -100,7 +100,7 @@ public final class KcOidcBrokerTest extends AbstractAdvancedBrokerTest {
|
|||
IdentityProviderMapperRepresentation attrMapper2 = new IdentityProviderMapperRepresentation();
|
||||
attrMapper2.setName("user-role-mapper");
|
||||
attrMapper2.setIdentityProviderMapper(ExternalKeycloakRoleToRoleMapper.PROVIDER_ID);
|
||||
attrMapper2.setConfig(ImmutableMap.<String,String>builder()
|
||||
attrMapper2.setConfig(ImmutableMap.<String, String>builder()
|
||||
.put(IdentityProviderMapperModel.SYNC_MODE, syncMode.toString())
|
||||
.put("external.role", ROLE_USER)
|
||||
.put("role", ROLE_USER)
|
||||
|
@ -114,7 +114,7 @@ public final class KcOidcBrokerTest extends AbstractAdvancedBrokerTest {
|
|||
IdentityProviderMapperRepresentation friendlyManagerMapper = new IdentityProviderMapperRepresentation();
|
||||
friendlyManagerMapper.setName("friendly-manager-role-mapper");
|
||||
friendlyManagerMapper.setIdentityProviderMapper(ExternalKeycloakRoleToRoleMapper.PROVIDER_ID);
|
||||
friendlyManagerMapper.setConfig(ImmutableMap.<String,String>builder()
|
||||
friendlyManagerMapper.setConfig(ImmutableMap.<String, String>builder()
|
||||
.put(IdentityProviderMapperModel.SYNC_MODE, syncMode.toString())
|
||||
.put("external.role", ROLE_FRIENDLY_MANAGER)
|
||||
.put("role", ROLE_FRIENDLY_MANAGER)
|
||||
|
@ -197,7 +197,7 @@ public final class KcOidcBrokerTest extends AbstractAdvancedBrokerTest {
|
|||
|
||||
logInWithBroker(bc);
|
||||
|
||||
waitForPage(driver, loginIsDenied? "We are sorry..." : "update account information", false);
|
||||
waitForPage(driver, loginIsDenied ? "We are sorry..." : "update account information", false);
|
||||
if (loginIsDenied) {
|
||||
return;
|
||||
}
|
||||
|
@ -243,7 +243,7 @@ public final class KcOidcBrokerTest extends AbstractAdvancedBrokerTest {
|
|||
ClientRepresentation brokerApp = clients.findByClientId("brokerapp").get(0);
|
||||
IdentityProviderResource identityProviderResource = getIdentityProviderResource();
|
||||
|
||||
clients.get(brokerApp.getId()).getProtocolMappers().createMapper(createHardcodedClaim("hard-coded", "hard-coded", "hard-coded", "String", true, true)).close();
|
||||
clients.get(brokerApp.getId()).getProtocolMappers().createMapper(createHardcodedClaim("hard-coded", "hard-coded", "hard-coded", "String", true, true, true)).close();
|
||||
|
||||
IdentityProviderMapperRepresentation hardCodedSessionNoteMapper = new IdentityProviderMapperRepresentation();
|
||||
|
||||
|
@ -445,7 +445,7 @@ public final class KcOidcBrokerTest extends AbstractAdvancedBrokerTest {
|
|||
RealmResource realm = adminClient.realm(bc.providerRealmName());
|
||||
ClientRepresentation rep = realm.clients().findByClientId(BrokerTestConstants.CLIENT_ID).get(0);
|
||||
ClientResource clientResource = realm.clients().get(rep.getId());
|
||||
ProtocolMapperRepresentation hardCodedAzp = createHardcodedClaim("hard", "azp", "invalid-azp", ProviderConfigProperty.STRING_TYPE, true, true);
|
||||
ProtocolMapperRepresentation hardCodedAzp = createHardcodedClaim("hard", "azp", "invalid-azp", ProviderConfigProperty.STRING_TYPE, true, true, true);
|
||||
clientResource.getProtocolMappers().createMapper(hardCodedAzp);
|
||||
|
||||
log.debug("Logging in");
|
||||
|
@ -469,7 +469,7 @@ public final class KcOidcBrokerTest extends AbstractAdvancedBrokerTest {
|
|||
RealmResource realm = adminClient.realm(bc.providerRealmName());
|
||||
ClientRepresentation rep = realm.clients().findByClientId(BrokerTestConstants.CLIENT_ID).get(0);
|
||||
ClientResource clientResource = realm.clients().get(rep.getId());
|
||||
ProtocolMapperRepresentation hardCodedAzp = createHardcodedClaim("hard", "aud", "invalid-aud", ProviderConfigProperty.LIST_TYPE, true, true);
|
||||
ProtocolMapperRepresentation hardCodedAzp = createHardcodedClaim("hard", "aud", "invalid-aud", ProviderConfigProperty.LIST_TYPE, true, true, true);
|
||||
clientResource.getProtocolMappers().createMapper(hardCodedAzp);
|
||||
|
||||
log.debug("Logging in");
|
||||
|
@ -564,7 +564,7 @@ public final class KcOidcBrokerTest extends AbstractAdvancedBrokerTest {
|
|||
|
||||
loginFetchingUserFromUserEndpoint(true);
|
||||
Assert.assertEquals("The ID token issued by the identity provider does not match the configured essential claim. Please contact your administrator.",
|
||||
loginPage.getInstruction());
|
||||
loginPage.getInstruction());
|
||||
|
||||
|
||||
List<UserRepresentation> users = realmsResouce().realm(bc.consumerRealmName()).users().search(bc.getUserLogin());
|
||||
|
@ -572,8 +572,8 @@ public final class KcOidcBrokerTest extends AbstractAdvancedBrokerTest {
|
|||
}
|
||||
|
||||
protected void postInitializeUser(UserRepresentation user) {
|
||||
user.setAttributes(ImmutableMap.<String, List<String>> builder()
|
||||
.put(USER_ATTRIBUTE_NAME, ImmutableList.<String> builder().add(USER_ATTRIBUTE_VALUE).build())
|
||||
user.setAttributes(ImmutableMap.<String, List<String>>builder()
|
||||
.put(USER_ATTRIBUTE_NAME, ImmutableList.<String>builder().add(USER_ATTRIBUTE_VALUE).build())
|
||||
.build());
|
||||
}
|
||||
|
||||
|
@ -585,8 +585,8 @@ public final class KcOidcBrokerTest extends AbstractAdvancedBrokerTest {
|
|||
assertThat(claimFilterValue, Matchers.notNullValue());
|
||||
|
||||
if (idProvider.getConfig().getOrDefault(IdentityProviderModel.FILTERED_BY_CLAIMS, "false").equals(Boolean.toString(filteredByClaim)) &&
|
||||
idProvider.getConfig().getOrDefault(IdentityProviderModel.CLAIM_FILTER_NAME, "").equals(claimFilterName) &&
|
||||
idProvider.getConfig().getOrDefault(IdentityProviderModel.CLAIM_FILTER_VALUE, "").equals(claimFilterValue)
|
||||
idProvider.getConfig().getOrDefault(IdentityProviderModel.CLAIM_FILTER_NAME, "").equals(claimFilterName) &&
|
||||
idProvider.getConfig().getOrDefault(IdentityProviderModel.CLAIM_FILTER_VALUE, "").equals(claimFilterValue)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
@ -722,7 +722,7 @@ public final class KcOidcBrokerTest extends AbstractAdvancedBrokerTest {
|
|||
}
|
||||
|
||||
private void updateIdPSyncMode(IdentityProviderRepresentation idProvider, IdentityProviderResource idProviderResource,
|
||||
IdentityProviderSyncMode syncMode, boolean trustEmail) {
|
||||
IdentityProviderSyncMode syncMode, boolean trustEmail) {
|
||||
assertThat(idProvider, Matchers.notNullValue());
|
||||
assertThat(idProviderResource, Matchers.notNullValue());
|
||||
assertThat(syncMode, Matchers.notNullValue());
|
||||
|
@ -755,6 +755,7 @@ public final class KcOidcBrokerTest extends AbstractAdvancedBrokerTest {
|
|||
}
|
||||
|
||||
private static final CustomKcOidcBrokerConfiguration BROKER_CONFIG_INSTANCE = new CustomKcOidcBrokerConfiguration();
|
||||
|
||||
static class CustomKcOidcBrokerConfiguration extends KcOidcBrokerConfiguration {
|
||||
|
||||
@Override
|
||||
|
@ -766,7 +767,7 @@ public final class KcOidcBrokerTest extends AbstractAdvancedBrokerTest {
|
|||
userAttrMapper.setName(USER_ATTRIBUTE_NAME);
|
||||
userAttrMapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
|
||||
userAttrMapper.setProtocolMapper(UserAttributeMapper.PROVIDER_ID);
|
||||
|
||||
|
||||
Map<String, String> userAttrMapperConfig = userAttrMapper.getConfig();
|
||||
userAttrMapperConfig.put(ProtocolMapperUtils.USER_ATTRIBUTE, USER_ATTRIBUTE_NAME);
|
||||
userAttrMapperConfig.put(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, USER_ATTRIBUTE_NAME);
|
||||
|
@ -781,6 +782,6 @@ public final class KcOidcBrokerTest extends AbstractAdvancedBrokerTest {
|
|||
client.setProtocolMappers(mappers);
|
||||
|
||||
return clients;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,18 +50,16 @@ import org.keycloak.representations.idm.ClientRepresentation;
|
|||
import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.ClientPolicyRepresentation;
|
||||
import org.keycloak.representations.idm.authorization.DecisionStrategy;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissionManagement;
|
||||
import org.keycloak.services.resources.admin.permissions.AdminPermissions;
|
||||
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
|
||||
import org.keycloak.testsuite.arquillian.annotation.EnableFeatures;
|
||||
import org.keycloak.testsuite.util.AdminClientUtil;
|
||||
import org.keycloak.testsuite.util.ClientBuilder;
|
||||
import org.keycloak.testsuite.util.OAuthClient;
|
||||
import org.keycloak.util.BasicAuthHelper;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
@EnableFeatures({ @EnableFeature(Profile.Feature.TOKEN_EXCHANGE), @EnableFeature(Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ) })
|
||||
@EnableFeatures({@EnableFeature(Profile.Feature.TOKEN_EXCHANGE), @EnableFeature(Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ)})
|
||||
public final class KcOidcBrokerTokenExchangeTest extends AbstractInitializedBaseBrokerTest {
|
||||
|
||||
@Override
|
||||
|
@ -77,7 +75,7 @@ public final class KcOidcBrokerTokenExchangeTest extends AbstractInitializedBase
|
|||
brokerApp.setDirectAccessGrantsEnabled(true);
|
||||
ClientResource brokerAppResource = providerRealm.clients().get(brokerApp.getId());
|
||||
brokerAppResource.update(brokerApp);
|
||||
brokerAppResource.getProtocolMappers().createMapper(createHardcodedClaim("hard-coded", "hard-coded", "hard-coded", "String", true, true)).close();
|
||||
brokerAppResource.getProtocolMappers().createMapper(createHardcodedClaim("hard-coded", "hard-coded", "hard-coded", "String", true, true, true)).close();
|
||||
|
||||
IdentityProviderMapperRepresentation hardCodedSessionNoteMapper = new IdentityProviderMapperRepresentation();
|
||||
hardCodedSessionNoteMapper.setName("hard-coded");
|
||||
|
|
|
@ -47,6 +47,7 @@ import org.keycloak.testsuite.util.AccountHelper;
|
|||
import org.keycloak.testsuite.util.OAuthClient;
|
||||
import org.keycloak.testsuite.util.TestAppHelper;
|
||||
|
||||
|
||||
import static org.keycloak.testsuite.admin.ApiUtil.findClientByClientId;
|
||||
|
||||
/**
|
||||
|
@ -180,7 +181,7 @@ public abstract class AbstractKerberosSingleRealmTest extends AbstractKerberosTe
|
|||
ProtocolMapperModel protocolMapper = UserSessionNoteMapper.createClaimMapper(KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME,
|
||||
KerberosConstants.GSS_DELEGATION_CREDENTIAL,
|
||||
KerberosConstants.GSS_DELEGATION_CREDENTIAL, "String",
|
||||
true, false, true);
|
||||
true, false, true, true);
|
||||
ProtocolMapperRepresentation protocolMapperRep = ModelToRepresentation.toRepresentation(protocolMapper);
|
||||
ClientResource clientResource = findClientByClientId(testRealmResource(), "kerberos-app");
|
||||
Response response = clientResource.getProtocolMappers().createMapper(protocolMapperRep);
|
||||
|
|
|
@ -105,8 +105,8 @@ public class LDAPMultipleAttributesTest extends AbstractLDAPTest {
|
|||
ldapClient.addRedirectUri("/ldap-portal");
|
||||
ldapClient.addRedirectUri("/ldap-portal/*");
|
||||
ldapClient.setManagementUrl("/ldap-portal");
|
||||
ldapClient.addProtocolMapper(UserAttributeMapper.createClaimMapper("postalCode", "postal_code", "postal_code", "String", true, true, true));
|
||||
ldapClient.addProtocolMapper(UserAttributeMapper.createClaimMapper("street", "street", "street", "String", true, true, false));
|
||||
ldapClient.addProtocolMapper(UserAttributeMapper.createClaimMapper("postalCode", "postal_code", "postal_code", "String", true, true, true, true));
|
||||
ldapClient.addProtocolMapper(UserAttributeMapper.createClaimMapper("street", "street", "street", "String", true, true, true, false));
|
||||
ldapClient.addScopeMapping(appRealm.getRole("user"));
|
||||
ldapClient.setSecret("password");
|
||||
});
|
||||
|
@ -237,7 +237,6 @@ public class LDAPMultipleAttributesTest extends AbstractLDAPTest {
|
|||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -819,7 +819,7 @@ public class AccessTokenTest extends AbstractKeycloakTest {
|
|||
String clientScopeId = ApiUtil.getCreatedId(response);
|
||||
response.close();
|
||||
ClientScopeResource clientScopeResource = adminClient.proxy(ClientScopeResource.class, scopeUri);
|
||||
ProtocolMapperModel hard = HardcodedClaim.create("hard", "hard", "coded", "String", true, true);
|
||||
ProtocolMapperModel hard = HardcodedClaim.create("hard", "hard", "coded", "String", true, true, true);
|
||||
ProtocolMapperRepresentation mapper = ModelToRepresentation.toRepresentation(hard);
|
||||
response = clientScopeResource.getProtocolMappers().createMapper(mapper);
|
||||
assertEquals(201, response.getStatus());
|
||||
|
|
|
@ -175,7 +175,7 @@ public class ClientTokenExchangeTest extends AbstractKeycloakTest {
|
|||
directPublic.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
|
||||
directPublic.setFullScopeAllowed(false);
|
||||
directPublic.addRedirectUri("*");
|
||||
directPublic.addProtocolMapper(AudienceProtocolMapper.createClaimMapper("client-exchanger-audience", clientExchanger.getClientId(), null, true, false));
|
||||
directPublic.addProtocolMapper(AudienceProtocolMapper.createClaimMapper("client-exchanger-audience", clientExchanger.getClientId(), null, true, false, true));
|
||||
|
||||
ClientModel directUntrustedPublic = realm.addClient("direct-public-untrusted");
|
||||
directUntrustedPublic.setClientId("direct-public-untrusted");
|
||||
|
@ -186,7 +186,7 @@ public class ClientTokenExchangeTest extends AbstractKeycloakTest {
|
|||
directUntrustedPublic.setFullScopeAllowed(false);
|
||||
directUntrustedPublic.addRedirectUri("*");
|
||||
directUntrustedPublic.setAttribute(OIDCConfigAttributes.POST_LOGOUT_REDIRECT_URIS, "+");
|
||||
directUntrustedPublic.addProtocolMapper(AudienceProtocolMapper.createClaimMapper("client-exchanger-audience", clientExchanger.getClientId(), null, true, false));
|
||||
directUntrustedPublic.addProtocolMapper(AudienceProtocolMapper.createClaimMapper("client-exchanger-audience", clientExchanger.getClientId(), null, true, false, true));
|
||||
|
||||
ClientModel directNoSecret = realm.addClient("direct-no-secret");
|
||||
directNoSecret.setClientId("direct-no-secret");
|
||||
|
@ -538,16 +538,16 @@ public class ClientTokenExchangeTest extends AbstractKeycloakTest {
|
|||
}
|
||||
|
||||
try (Response response = exchangeUrl.request()
|
||||
.header(HttpHeaders.AUTHORIZATION, BasicAuthHelper.createHeader("client-exchanger", "secret"))
|
||||
.post(Entity.form(
|
||||
new Form()
|
||||
.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.TOKEN_EXCHANGE_GRANT_TYPE)
|
||||
.param(OAuth2Constants.SUBJECT_TOKEN, accessToken)
|
||||
.param(OAuth2Constants.SUBJECT_TOKEN_TYPE, OAuth2Constants.ACCESS_TOKEN_TYPE)
|
||||
.param(OAuth2Constants.REQUESTED_SUBJECT, "impersonated-user")
|
||||
.param(OAuth2Constants.AUDIENCE, "target")
|
||||
.header(HttpHeaders.AUTHORIZATION, BasicAuthHelper.createHeader("client-exchanger", "secret"))
|
||||
.post(Entity.form(
|
||||
new Form()
|
||||
.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.TOKEN_EXCHANGE_GRANT_TYPE)
|
||||
.param(OAuth2Constants.SUBJECT_TOKEN, accessToken)
|
||||
.param(OAuth2Constants.SUBJECT_TOKEN_TYPE, OAuth2Constants.ACCESS_TOKEN_TYPE)
|
||||
.param(OAuth2Constants.REQUESTED_SUBJECT, "impersonated-user")
|
||||
.param(OAuth2Constants.AUDIENCE, "target")
|
||||
|
||||
))) {
|
||||
))) {
|
||||
org.junit.Assert.assertEquals(200, response.getStatus());
|
||||
AccessTokenResponse accessTokenResponse = response.readEntity(AccessTokenResponse.class);
|
||||
String exchangedTokenString = accessTokenResponse.getToken();
|
||||
|
|
|
@ -401,7 +401,7 @@ public class OAuthGrantTest extends AbstractKeycloakTest {
|
|||
String fooScopeId = ApiUtil.getCreatedId(response);
|
||||
response.close();
|
||||
|
||||
ProtocolMapperRepresentation protocolMapper = ProtocolMapperUtil.createAddressMapper(true, true, true);
|
||||
ProtocolMapperRepresentation protocolMapper = ProtocolMapperUtil.createAddressMapper(true, true, true, true);
|
||||
response = appRealm.clientScopes().get(fooScopeId).getProtocolMappers().createMapper(protocolMapper);
|
||||
response.close();
|
||||
|
||||
|
|
|
@ -153,11 +153,11 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
reconnectAdminClient();
|
||||
ClientResource app = findClientResourceByClientId(adminClient.realm("test"), "test-app");
|
||||
|
||||
app.getProtocolMappers().createMapper(createScriptMapper("test-script-mapper1","computed-via-script", "computed-via-script", "String", true, true, "script-scripts/test-script-mapper1.js", false)).close();
|
||||
app.getProtocolMappers().createMapper(createScriptMapper("test-script-mapper2","multiValued-via-script", "multiValued-via-script", "String", true, true, "script-scripts/test-script-mapper2.js", true)).close();
|
||||
app.getProtocolMappers().createMapper(createScriptMapper("test-script-mapper3","computed-json-via-script", "computed-json-via-script", "JSON", true, true, "script-scripts/test-script-mapper3.js", false)).close();
|
||||
app.getProtocolMappers().createMapper(createScriptMapper("test-script-mapper1","computed-via-script", "computed-via-script", "String", true, true, true,"script-scripts/test-script-mapper1.js", false)).close();
|
||||
app.getProtocolMappers().createMapper(createScriptMapper("test-script-mapper2","multiValued-via-script", "multiValued-via-script", "String", true, true, true, "script-scripts/test-script-mapper2.js", true)).close();
|
||||
app.getProtocolMappers().createMapper(createScriptMapper("test-script-mapper3","computed-json-via-script", "computed-json-via-script", "JSON", true, true, true, "script-scripts/test-script-mapper3.js", false)).close();
|
||||
|
||||
Response response = app.getProtocolMappers().createMapper(createScriptMapper("test-script-mapper3", "syntax-error-script", "syntax-error-script", "String", true, true, "script-scripts/test-bad-script-mapper3.js", false));
|
||||
Response response = app.getProtocolMappers().createMapper(createScriptMapper("test-script-mapper3", "syntax-error-script", "syntax-error-script", "String", true, true, true, "script-scripts/test-bad-script-mapper3.js", false));
|
||||
assertThat(response.getStatusInfo().getFamily(), is(Response.Status.Family.CLIENT_ERROR));
|
||||
response.close();
|
||||
}
|
||||
|
@ -199,31 +199,31 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
|
||||
ClientResource app = findClientResourceByClientId(adminClient.realm("test"), "test-app");
|
||||
|
||||
ProtocolMapperRepresentation mapper = createAddressMapper(true, true, true);
|
||||
ProtocolMapperRepresentation mapper = createAddressMapper(true, true, true, true);
|
||||
mapper.getConfig().put(AddressMapper.getModelPropertyName(AddressClaimSet.REGION), "region_some");
|
||||
mapper.getConfig().put(AddressMapper.getModelPropertyName(AddressClaimSet.COUNTRY), "country_some");
|
||||
mapper.getConfig().remove(AddressMapper.getModelPropertyName(AddressClaimSet.POSTAL_CODE)); // Even if we remove protocolMapper config property, it should still default to postal_code
|
||||
app.getProtocolMappers().createMapper(mapper).close();
|
||||
|
||||
ProtocolMapperRepresentation hard = createHardcodedClaim("hard", "hard", "coded", "String", true, true);
|
||||
ProtocolMapperRepresentation hard = createHardcodedClaim("hard", "hard", "coded", "String", true, true, true);
|
||||
app.getProtocolMappers().createMapper(hard).close();
|
||||
app.getProtocolMappers().createMapper(createHardcodedClaim("hard-nested", "nested.hard", "coded-nested", "String", true, true)).close();
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("custom phone", "phone", "home_phone", "String", true, true, true)).close();
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("nested phone", "phone", "home.phone", "String", true, true, true)).close();
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("dotted phone", "phone", "home\\.phone", "String", true, true, true)).close();
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("departments", "departments", "department", "String", true, true, true)).close();
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("firstDepartment", "departments", "firstDepartment", "String", true, true, false)).close();
|
||||
app.getProtocolMappers().createMapper(createHardcodedClaim("hard-nested", "nested.hard", "coded-nested", "String", true, true, true)).close();
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("custom phone", "phone", "home_phone", "String", true, true, true, true)).close();
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("nested phone", "phone", "home.phone", "String", true, true, true, true)).close();
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("dotted phone", "phone", "home\\.phone", "String", true, true, true, true)).close();
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("departments", "departments", "department", "String", true, true, true, true)).close();
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("firstDepartment", "departments", "firstDepartment", "String", true, true, true,false)).close();
|
||||
app.getProtocolMappers().createMapper(createHardcodedRole("hard-realm", "hardcoded")).close();
|
||||
app.getProtocolMappers().createMapper(createHardcodedRole("hard-app", "app.hardcoded")).close();
|
||||
app.getProtocolMappers().createMapper(createRoleNameMapper("rename-app-role", "test-app.customer-user", "realm-user")).close();
|
||||
app.getProtocolMappers().createMapper(createScriptMapper("test-script-mapper1","computed-via-script", "computed-via-script", "String", true, true, "'hello_' + user.username", false)).close();
|
||||
app.getProtocolMappers().createMapper(createScriptMapper("test-script-mapper2","multiValued-via-script", "multiValued-via-script", "String", true, true, "new java.util.ArrayList(['A','B'])", true)).close();
|
||||
app.getProtocolMappers().createMapper(createScriptMapper("test-script-mapper1","computed-via-script", "computed-via-script", "String", true, true, true, "'hello_' + user.username", false)).close();
|
||||
app.getProtocolMappers().createMapper(createScriptMapper("test-script-mapper2","multiValued-via-script", "multiValued-via-script", "String", true, true, true, "new java.util.ArrayList(['A','B'])", true)).close();
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("json-attribute-mapper", "json-attribute", "claim-from-json-attribute",
|
||||
"JSON", true, true, false)).close();
|
||||
"JSON", true, true, true, false)).close();
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("json-attribute-mapper-multi", "json-attribute-multi", "claim-from-json-attribute-multi",
|
||||
"JSON", true, true, true)).close();
|
||||
"JSON", true, true, true, true)).close();
|
||||
|
||||
Response response = app.getProtocolMappers().createMapper(createScriptMapper("test-script-mapper3", "syntax-error-script", "syntax-error-script", "String", true, true, "func_tion foo(){ return 'fail';} foo()", false));
|
||||
Response response = app.getProtocolMappers().createMapper(createScriptMapper("test-script-mapper3", "syntax-error-script", "syntax-error-script", "String", true, true, true, "func_tion foo(){ return 'fail';} foo()", false));
|
||||
assertThat(response.getStatusInfo().getFamily(), is(Response.Status.Family.CLIENT_ERROR));
|
||||
response.close();
|
||||
}
|
||||
|
@ -360,10 +360,10 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
|
||||
// create a user attr mapping for some claims that exist as properties in the tokens
|
||||
ClientResource app = findClientResourceByClientId(adminClient.realm("test"), "test-app");
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("userid-as-sub", "userid", "sub", "String", true, true, false)).close();
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("useraud", "useraud", "aud", "String", true, true, true)).close();
|
||||
app.getProtocolMappers().createMapper(createHardcodedClaim("website-hardcoded", "website", "http://localhost", "String", true, true)).close();
|
||||
app.getProtocolMappers().createMapper(createHardcodedClaim("iat-hardcoded", "iat", "123", "long", true, false)).close();
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("userid-as-sub", "userid", "sub", "String", true, true, true,false)).close();
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("useraud", "useraud", "aud", "String", true, true, true, true)).close();
|
||||
app.getProtocolMappers().createMapper(createHardcodedClaim("website-hardcoded", "website", "http://localhost", "String", true, true, true)).close();
|
||||
app.getProtocolMappers().createMapper(createHardcodedClaim("iat-hardcoded", "iat", "123", "long", true, false, true)).close();
|
||||
|
||||
// login
|
||||
OAuthClient.AccessTokenResponse response = browserLogin("password", "test-user@localhost", "password");
|
||||
|
@ -432,6 +432,7 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
"claim-name",
|
||||
String.class.getSimpleName(),
|
||||
true,
|
||||
true,
|
||||
true
|
||||
)))) {
|
||||
mapperId = getCreatedId(response);
|
||||
|
@ -481,6 +482,7 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
"claim-name",
|
||||
String.class.getSimpleName(),
|
||||
true,
|
||||
true,
|
||||
true
|
||||
)))) {
|
||||
mapperId = getCreatedId(response);
|
||||
|
@ -519,8 +521,8 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
userResource.update(user);
|
||||
|
||||
ClientResource app = findClientResourceByClientId(adminClient.realm("test"), "test-app");
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("empty", "empty", "empty", "String", true, true, false)).close();
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("null", "null", "null", "String", true, true, false)).close();
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("empty", "empty", "empty", "String", true, true, true,false)).close();
|
||||
app.getProtocolMappers().createMapper(createClaimMapper("null", "null", "null", "String", true, true, true,false)).close();
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -569,8 +571,8 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
|
||||
public void testUserRoleToAttributeMappers() throws Exception {
|
||||
// Add mapper for realm roles
|
||||
ProtocolMapperRepresentation realmMapper = ProtocolMapperUtil.createUserRealmRoleMappingMapper("pref.", "Realm roles mapper", "roles-custom.realm", true, true);
|
||||
ProtocolMapperRepresentation clientMapper = ProtocolMapperUtil.createUserClientRoleMappingMapper("test-app", null, "Client roles mapper", "roles-custom.test-app", true, true);
|
||||
ProtocolMapperRepresentation realmMapper = ProtocolMapperUtil.createUserRealmRoleMappingMapper("pref.", "Realm roles mapper", "roles-custom.realm", true, true, true);
|
||||
ProtocolMapperRepresentation clientMapper = ProtocolMapperUtil.createUserClientRoleMappingMapper("test-app", null, "Client roles mapper", "roles-custom.test-app", true, true, true);
|
||||
|
||||
ProtocolMappersResource protocolMappers = ApiUtil.findClientResourceByClientId(adminClient.realm("test"), "test-app").getProtocolMappers();
|
||||
protocolMappers.createMapper(Arrays.asList(realmMapper, clientMapper));
|
||||
|
@ -792,7 +794,7 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
public void testRoleMapperWithRoleInheritedFromMoreGroups() throws Exception {
|
||||
// Create client-mapper
|
||||
String clientId = "test-app";
|
||||
ProtocolMapperRepresentation clientMapper = ProtocolMapperUtil.createUserClientRoleMappingMapper(clientId, null, "Client roles mapper", "roles-custom.test-app", true, true);
|
||||
ProtocolMapperRepresentation clientMapper = ProtocolMapperUtil.createUserClientRoleMappingMapper(clientId, null, "Client roles mapper", "roles-custom.test-app", true, true, true);
|
||||
|
||||
ProtocolMappersResource protocolMappers = ApiUtil.findClientResourceByClientId(adminClient.realm("test"), clientId).getProtocolMappers();
|
||||
protocolMappers.createMapper(Arrays.asList(clientMapper));
|
||||
|
@ -825,8 +827,8 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
public void testUserGroupRoleToAttributeMappers() throws Exception {
|
||||
// Add mapper for realm roles
|
||||
String clientId = "test-app";
|
||||
ProtocolMapperRepresentation realmMapper = ProtocolMapperUtil.createUserRealmRoleMappingMapper("pref.", "Realm roles mapper", "roles-custom.realm", true, true);
|
||||
ProtocolMapperRepresentation clientMapper = ProtocolMapperUtil.createUserClientRoleMappingMapper(clientId, "ta.", "Client roles mapper", "roles-custom.test-app", true, true);
|
||||
ProtocolMapperRepresentation realmMapper = ProtocolMapperUtil.createUserRealmRoleMappingMapper("pref.", "Realm roles mapper", "roles-custom.realm", true, true, true);
|
||||
ProtocolMapperRepresentation clientMapper = ProtocolMapperUtil.createUserClientRoleMappingMapper(clientId, "ta.", "Client roles mapper", "roles-custom.test-app", true, true, true);
|
||||
|
||||
ProtocolMappersResource protocolMappers = ApiUtil.findClientResourceByClientId(adminClient.realm("test"), clientId).getProtocolMappers();
|
||||
protocolMappers.createMapper(Arrays.asList(realmMapper, clientMapper));
|
||||
|
@ -861,8 +863,8 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
@Test
|
||||
public void testUserGroupRoleToAttributeMappersNotScopedOtherApp() throws Exception {
|
||||
String clientId = "test-app-authz";
|
||||
ProtocolMapperRepresentation realmMapper = ProtocolMapperUtil.createUserRealmRoleMappingMapper("pref.", "Realm roles mapper", "roles-custom.realm", true, true);
|
||||
ProtocolMapperRepresentation clientMapper = ProtocolMapperUtil.createUserClientRoleMappingMapper(clientId, null, "Client roles mapper", "roles-custom." + clientId, true, true);
|
||||
ProtocolMapperRepresentation realmMapper = ProtocolMapperUtil.createUserRealmRoleMappingMapper("pref.", "Realm roles mapper", "roles-custom.realm", true, true, true);
|
||||
ProtocolMapperRepresentation clientMapper = ProtocolMapperUtil.createUserClientRoleMappingMapper(clientId, null, "Client roles mapper", "roles-custom." + clientId, true, true, true);
|
||||
|
||||
ProtocolMappersResource protocolMappers = ApiUtil.findClientResourceByClientId(adminClient.realm("test"), clientId).getProtocolMappers();
|
||||
protocolMappers.createMapper(Arrays.asList(realmMapper, clientMapper));
|
||||
|
@ -901,8 +903,8 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
@Test
|
||||
public void testUserGroupRoleToAttributeMappersScoped() throws Exception {
|
||||
String clientId = "test-app-scope";
|
||||
ProtocolMapperRepresentation realmMapper = ProtocolMapperUtil.createUserRealmRoleMappingMapper("pref.", "Realm roles mapper", "roles-custom.realm", true, true);
|
||||
ProtocolMapperRepresentation clientMapper = ProtocolMapperUtil.createUserClientRoleMappingMapper(clientId, null, "Client roles mapper", "roles-custom.test-app-scope", true, true);
|
||||
ProtocolMapperRepresentation realmMapper = ProtocolMapperUtil.createUserRealmRoleMappingMapper("pref.", "Realm roles mapper", "roles-custom.realm", true, true, true);
|
||||
ProtocolMapperRepresentation clientMapper = ProtocolMapperUtil.createUserClientRoleMappingMapper(clientId, null, "Client roles mapper", "roles-custom.test-app-scope", true, true, true);
|
||||
|
||||
ProtocolMappersResource protocolMappers = ApiUtil.findClientResourceByClientId(adminClient.realm("test"), clientId).getProtocolMappers();
|
||||
protocolMappers.createMapper(Arrays.asList(realmMapper, clientMapper));
|
||||
|
@ -935,8 +937,8 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
@Test
|
||||
public void testUserGroupRoleToAttributeMappersScopedClientNotSet() throws Exception {
|
||||
String clientId = "test-app-scope";
|
||||
ProtocolMapperRepresentation realmMapper = ProtocolMapperUtil.createUserRealmRoleMappingMapper("pref.", "Realm roles mapper", "roles-custom.realm", true, true);
|
||||
ProtocolMapperRepresentation clientMapper = ProtocolMapperUtil.createUserClientRoleMappingMapper(null, null, "Client roles mapper", "roles-custom.test-app-scope", true, true);
|
||||
ProtocolMapperRepresentation realmMapper = ProtocolMapperUtil.createUserRealmRoleMappingMapper("pref.", "Realm roles mapper", "roles-custom.realm", true, true, true);
|
||||
ProtocolMapperRepresentation clientMapper = ProtocolMapperUtil.createUserClientRoleMappingMapper(null, null, "Client roles mapper", "roles-custom.test-app-scope", true, true, true);
|
||||
|
||||
ProtocolMappersResource protocolMappers = ApiUtil.findClientResourceByClientId(adminClient.realm("test"), clientId).getProtocolMappers();
|
||||
protocolMappers.createMapper(Arrays.asList(realmMapper, clientMapper));
|
||||
|
@ -971,8 +973,8 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
@Test
|
||||
public void testSingleValuedRoleMapping() throws Exception {
|
||||
String clientId = "test-app-scope";
|
||||
ProtocolMapperRepresentation realmMapper = ProtocolMapperUtil.createUserRealmRoleMappingMapper("pref.", "Realm roles mapper", "roles-custom.realm", true, true, false);
|
||||
ProtocolMapperRepresentation clientMapper = ProtocolMapperUtil.createUserClientRoleMappingMapper(null, null, "Client roles mapper", "roles-custom.test-app-scope", true, true, false);
|
||||
ProtocolMapperRepresentation realmMapper = ProtocolMapperUtil.createUserRealmRoleMappingMapper("pref.", "Realm roles mapper", "roles-custom.realm", true, true, true,false);
|
||||
ProtocolMapperRepresentation clientMapper = ProtocolMapperUtil.createUserClientRoleMappingMapper(null, null, "Client roles mapper", "roles-custom.test-app-scope", true, true, true, false);
|
||||
|
||||
ProtocolMappersResource protocolMappers = ApiUtil.findClientResourceByClientId(adminClient.realm("test"), clientId).getProtocolMappers();
|
||||
protocolMappers.createMapper(Arrays.asList(realmMapper, clientMapper));
|
||||
|
@ -1008,8 +1010,8 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
final String diffClient = "test-app";
|
||||
final String realmName = "test";
|
||||
|
||||
final ProtocolMapperRepresentation realmMapper = ProtocolMapperUtil.createUserRealmRoleMappingMapper("pref.", "Realm roles mapper", "roles-custom.realm", true, true);
|
||||
final ProtocolMapperRepresentation clientMapper = ProtocolMapperUtil.createUserClientRoleMappingMapper(diffClient, null, "Client roles mapper", "roles-custom.test-app", true, true);
|
||||
final ProtocolMapperRepresentation realmMapper = ProtocolMapperUtil.createUserRealmRoleMappingMapper("pref.", "Realm roles mapper", "roles-custom.realm", true, true, true);
|
||||
final ProtocolMapperRepresentation clientMapper = ProtocolMapperUtil.createUserClientRoleMappingMapper(diffClient, null, "Client roles mapper", "roles-custom.test-app", true, true, true);
|
||||
|
||||
try (ClientAttributeUpdater cau = ClientAttributeUpdater.forClient(adminClient, realmName, clientId).setDirectAccessGrantsEnabled(true);
|
||||
ProtocolMappersUpdater protocolMappers = new ProtocolMappersUpdater(cau.getResource().getProtocolMappers())) {
|
||||
|
@ -1057,7 +1059,7 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
userResource.joinGroup(group1.getId());
|
||||
// create the attribute mapper
|
||||
ProtocolMappersResource protocolMappers = findClientResourceByClientId(adminClient.realm("test"), "test-app").getProtocolMappers();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, false, false)).close();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, true,false, false)).close();
|
||||
|
||||
try {
|
||||
// test it
|
||||
|
@ -1097,7 +1099,7 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
userResource.joinGroup(group1.getId());
|
||||
// create the attribute mapper
|
||||
ProtocolMappersResource protocolMappers = findClientResourceByClientId(adminClient.realm("test"), "test-app").getProtocolMappers();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, true, false)).close();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, true, true, false)).close();
|
||||
|
||||
try {
|
||||
// test it
|
||||
|
@ -1138,7 +1140,7 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
userResource.joinGroup(group1.getId());
|
||||
// create the attribute mapper
|
||||
ProtocolMappersResource protocolMappers = findClientResourceByClientId(adminClient.realm("test"), "test-app").getProtocolMappers();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, true, true)).close();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, true, true, true)).close();
|
||||
|
||||
try {
|
||||
// test it
|
||||
|
@ -1177,7 +1179,7 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
userResource.joinGroup(group1.getId());
|
||||
// create the attribute mapper
|
||||
ProtocolMappersResource protocolMappers = findClientResourceByClientId(adminClient.realm("test"), "test-app").getProtocolMappers();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, false, false)).close();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, true, false, false)).close();
|
||||
|
||||
try {
|
||||
// test it
|
||||
|
@ -1212,7 +1214,7 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
|
||||
// create the attribute mapper
|
||||
ProtocolMappersResource protocolMappers = findClientResourceByClientId(adminClient.realm("test"), "test-app").getProtocolMappers();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, true, false)).close();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, true, true, false)).close();
|
||||
|
||||
try {
|
||||
// test it
|
||||
|
@ -1248,7 +1250,7 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
|
||||
// create the attribute mapper
|
||||
ProtocolMappersResource protocolMappers = findClientResourceByClientId(adminClient.realm("test"), "test-app").getProtocolMappers();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, true, true)).close();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, true, true, true)).close();
|
||||
|
||||
try {
|
||||
// test it
|
||||
|
@ -1291,7 +1293,7 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
|
||||
// create the attribute mapper
|
||||
ProtocolMappersResource protocolMappers = findClientResourceByClientId(adminClient.realm("test"), "test-app").getProtocolMappers();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, false, false)).close();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, true, false, false)).close();
|
||||
|
||||
try {
|
||||
// test it
|
||||
|
@ -1336,7 +1338,7 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
|
||||
// create the attribute mapper
|
||||
ProtocolMappersResource protocolMappers = findClientResourceByClientId(adminClient.realm("test"), "test-app").getProtocolMappers();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, true, false)).close();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, true, true, false)).close();
|
||||
|
||||
try {
|
||||
// test it
|
||||
|
@ -1383,7 +1385,7 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
|
||||
// create the attribute mapper
|
||||
ProtocolMappersResource protocolMappers = findClientResourceByClientId(adminClient.realm("test"), "test-app").getProtocolMappers();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, true, true)).close();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, true, true, true)).close();
|
||||
|
||||
try {
|
||||
// test it
|
||||
|
@ -1434,7 +1436,7 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
|
||||
// create the attribute mapper
|
||||
ProtocolMappersResource protocolMappers = findClientResourceByClientId(adminClient.realm("test"), "test-app").getProtocolMappers();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, false, false)).close();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, true, false, false)).close();
|
||||
|
||||
try {
|
||||
// test it
|
||||
|
@ -1483,7 +1485,7 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
|
||||
// create the attribute mapper
|
||||
ProtocolMappersResource protocolMappers = findClientResourceByClientId(adminClient.realm("test"), "test-app").getProtocolMappers();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, false, false)).close();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, true, false, false)).close();
|
||||
|
||||
try {
|
||||
// test it
|
||||
|
@ -1532,7 +1534,7 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
|
||||
// create the attribute mapper
|
||||
ProtocolMappersResource protocolMappers = findClientResourceByClientId(adminClient.realm("test"), "test-app").getProtocolMappers();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, true, false)).close();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, true, true, false)).close();
|
||||
|
||||
try {
|
||||
// test it
|
||||
|
@ -1586,7 +1588,7 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
|
||||
// create the attribute mapper
|
||||
ProtocolMappersResource protocolMappers = findClientResourceByClientId(adminClient.realm("test"), "test-app").getProtocolMappers();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, true, true)).close();
|
||||
protocolMappers.createMapper(createClaimMapper("group-value", "group-value", "group-value", "String", true, true, true,true, true)).close();
|
||||
|
||||
try {
|
||||
// test it
|
||||
|
@ -1776,7 +1778,7 @@ public class OIDCProtocolMappersTest extends AbstractKeycloakTest {
|
|||
put(ClientScopeModel.DYNAMIC_SCOPE_REGEXP, "dyn-scope-with-mapper:*");
|
||||
}});
|
||||
// create the attribute mapper
|
||||
ProtocolMapperRepresentation protocolMapperRepresentation = createHardcodedClaim("dynamic-scope-hardcoded-mapper", "hardcoded-foo", "hardcoded-bar", "String", true, true);
|
||||
ProtocolMapperRepresentation protocolMapperRepresentation = createHardcodedClaim("dynamic-scope-hardcoded-mapper", "hardcoded-foo", "hardcoded-bar", "String", true, true, true);
|
||||
scopeRep.setProtocolMappers(Collections.singletonList(protocolMapperRepresentation));
|
||||
|
||||
try (Response resp = adminClient.realm("test").clientScopes().create(scopeRep)) {
|
||||
|
|
|
@ -119,7 +119,7 @@ public class AudienceTest extends AbstractOIDCScopeTest {
|
|||
public void testAudienceProtocolMapperWithClientAudience() throws Exception {
|
||||
// Add audience protocol mapper to the clientScope "audience-scope"
|
||||
ProtocolMapperRepresentation audienceMapper = ProtocolMapperUtil.createAudienceMapper("audience mapper", "service-client",
|
||||
null, true, false);
|
||||
null, true, false, true);
|
||||
ClientScopeResource clientScope = ApiUtil.findClientScopeByName(testRealm(), "audience-scope");
|
||||
Response resp = clientScope.getProtocolMappers().createMapper(audienceMapper);
|
||||
String mapperId = ApiUtil.getCreatedId(resp);
|
||||
|
@ -131,7 +131,7 @@ public class AudienceTest extends AbstractOIDCScopeTest {
|
|||
EventRepresentation loginEvent = events.expectLogin()
|
||||
.user(userId)
|
||||
.assertEvent();
|
||||
Tokens tokens = sendTokenRequest(loginEvent, userId,"openid profile email audience-scope", "test-app");
|
||||
Tokens tokens = sendTokenRequest(loginEvent, userId, "openid profile email audience-scope", "test-app");
|
||||
|
||||
assertAudiences(tokens.accessToken, "service-client");
|
||||
assertAudiences(tokens.idToken, "test-app");
|
||||
|
@ -145,14 +145,14 @@ public class AudienceTest extends AbstractOIDCScopeTest {
|
|||
public void testAudienceProtocolMapperWithCustomAudience() throws Exception {
|
||||
// Add audience protocol mapper to the clientScope "audience-scope"
|
||||
ProtocolMapperRepresentation audienceMapper = ProtocolMapperUtil.createAudienceMapper("audience mapper 1", null,
|
||||
"http://host/service/ctx1", true, false);
|
||||
"http://host/service/ctx1", true, false, true);
|
||||
ClientScopeResource clientScope = ApiUtil.findClientScopeByName(testRealm(), "audience-scope");
|
||||
Response resp = clientScope.getProtocolMappers().createMapper(audienceMapper);
|
||||
String mapper1Id = ApiUtil.getCreatedId(resp);
|
||||
resp.close();
|
||||
|
||||
audienceMapper = ProtocolMapperUtil.createAudienceMapper("audience mapper 2", null,
|
||||
"http://host/service/ctx2", true, true);
|
||||
"http://host/service/ctx2", true, true, true);
|
||||
resp = clientScope.getProtocolMappers().createMapper(audienceMapper);
|
||||
String mapper2Id = ApiUtil.getCreatedId(resp);
|
||||
resp.close();
|
||||
|
@ -163,7 +163,7 @@ public class AudienceTest extends AbstractOIDCScopeTest {
|
|||
EventRepresentation loginEvent = events.expectLogin()
|
||||
.user(userId)
|
||||
.assertEvent();
|
||||
Tokens tokens = sendTokenRequest(loginEvent, userId,"openid profile email audience-scope", "test-app");
|
||||
Tokens tokens = sendTokenRequest(loginEvent, userId, "openid profile email audience-scope", "test-app");
|
||||
|
||||
assertAudiences(tokens.accessToken, "http://host/service/ctx1", "http://host/service/ctx2");
|
||||
assertAudiences(tokens.idToken, "test-app", "http://host/service/ctx2");
|
||||
|
|
|
@ -0,0 +1,472 @@
|
|||
package org.keycloak.testsuite.oidc;
|
||||
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.ClientScopeResource;
|
||||
import org.keycloak.admin.client.resource.ProtocolMappersResource;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import org.keycloak.protocol.oidc.mappers.AudienceProtocolMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.GroupMembershipMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.HardcodedClaim;
|
||||
import org.keycloak.protocol.oidc.mappers.HardcodedRole;
|
||||
import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
|
||||
import org.keycloak.protocol.oidc.mappers.RoleNameMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.SHA256PairwiseSubMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.UserSessionNoteMapper;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.testsuite.AbstractKeycloakTest;
|
||||
import org.keycloak.testsuite.admin.ApiUtil;
|
||||
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
|
||||
import org.keycloak.testsuite.util.ClientManager;
|
||||
import org.keycloak.testsuite.util.KeycloakModelUtils;
|
||||
import org.keycloak.testsuite.util.OAuthClient;
|
||||
import org.keycloak.testsuite.util.ProtocolMapperUtil;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
import org.wildfly.common.Assert;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.keycloak.protocol.ProtocolMapperUtils.USER_SESSION_NOTE;
|
||||
import static org.keycloak.protocol.oidc.OIDCLoginProtocolFactory.ACR;
|
||||
import static org.keycloak.protocol.oidc.OIDCLoginProtocolFactory.ACR_SCOPE;
|
||||
import static org.keycloak.protocol.oidc.OIDCLoginProtocolFactory.ADDRESS;
|
||||
import static org.keycloak.protocol.oidc.OIDCLoginProtocolFactory.ALLOWED_WEB_ORIGINS;
|
||||
import static org.keycloak.protocol.oidc.OIDCLoginProtocolFactory.AUDIENCE_RESOLVE;
|
||||
import static org.keycloak.protocol.oidc.OIDCLoginProtocolFactory.CLIENT_ROLES;
|
||||
import static org.keycloak.protocol.oidc.OIDCLoginProtocolFactory.EMAIL;
|
||||
import static org.keycloak.protocol.oidc.OIDCLoginProtocolFactory.EMAIL_VERIFIED;
|
||||
import static org.keycloak.protocol.oidc.OIDCLoginProtocolFactory.FAMILY_NAME;
|
||||
import static org.keycloak.protocol.oidc.OIDCLoginProtocolFactory.FULL_NAME;
|
||||
import static org.keycloak.protocol.oidc.OIDCLoginProtocolFactory.GIVEN_NAME;
|
||||
import static org.keycloak.protocol.oidc.OIDCLoginProtocolFactory.PROFILE_CLAIM;
|
||||
import static org.keycloak.protocol.oidc.OIDCLoginProtocolFactory.REALM_ROLES;
|
||||
import static org.keycloak.protocol.oidc.OIDCLoginProtocolFactory.ROLES_SCOPE;
|
||||
import static org.keycloak.protocol.oidc.OIDCLoginProtocolFactory.USERNAME;
|
||||
import static org.keycloak.protocol.oidc.OIDCLoginProtocolFactory.WEB_ORIGINS_SCOPE;
|
||||
import static org.keycloak.protocol.oidc.mappers.AbstractPairwiseSubMapper.PROVIDER_ID_SUFFIX;
|
||||
import static org.keycloak.protocol.oidc.mappers.AudienceProtocolMapper.INCLUDED_CLIENT_AUDIENCE;
|
||||
import static org.keycloak.protocol.oidc.mappers.HardcodedClaim.CLAIM_VALUE;
|
||||
import static org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN;
|
||||
import static org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper.INCLUDE_IN_INTROSPECTION;
|
||||
import static org.keycloak.protocol.oidc.mappers.PairwiseSubMapperHelper.PAIRWISE_SUB_ALGORITHM_SALT;
|
||||
import static org.keycloak.protocol.oidc.mappers.RoleNameMapper.NEW_ROLE_NAME;
|
||||
import static org.keycloak.protocol.oidc.mappers.RoleNameMapper.ROLE_CONFIG;
|
||||
import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
|
||||
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
|
||||
|
||||
@EnableFeature(value = Profile.Feature.TOKEN_EXCHANGE, skipRestart = true)
|
||||
public class LightWeightAccessTokenTest extends AbstractKeycloakTest {
|
||||
|
||||
@Before
|
||||
public void clientConfiguration() {
|
||||
ClientManager.realm(adminClient.realm("test")).clientId("test-app").directAccessGrant(true).setServiceAccountsEnabled(true);
|
||||
ClientManager.realm(adminClient.realm("test")).clientId("resource-server").directAccessGrant(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTestRealms(List<RealmRepresentation> testRealms) {
|
||||
RealmRepresentation realm = loadJson(getClass().getResourceAsStream("/testrealm.json"), RealmRepresentation.class);
|
||||
UserRepresentation user = findUser(realm, "test-user@localhost");
|
||||
Map<String, List<String>> attributes = new HashMap<>(){{
|
||||
put("street", Arrays.asList("1 My Street"));
|
||||
put("locality", Arrays.asList("Cardiff"));
|
||||
put("region", Arrays.asList("Cardiff"));
|
||||
put("postal_code", Arrays.asList("CF104RA"));
|
||||
}};
|
||||
user.setAttributes(attributes);
|
||||
user.setGroups(Arrays.asList("/topGroup/level2group"));
|
||||
ClientRepresentation confApp = KeycloakModelUtils.createClient(realm, "resource-server");
|
||||
confApp.setSecret("password");
|
||||
confApp.setServiceAccountsEnabled(Boolean.TRUE);
|
||||
testRealms.add(realm);
|
||||
}
|
||||
|
||||
private UserRepresentation findUser(RealmRepresentation testRealm, String userName) {
|
||||
for (UserRepresentation user : testRealm.getUsers()) {
|
||||
if (user.getUsername().equals(userName)) return user;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessTokenFalseIntrospectionTrueTest() throws IOException {
|
||||
ProtocolMappersResource protocolMappers = setProtocolMappers(false, true, true);
|
||||
try {
|
||||
oauth.nonce("123456");
|
||||
oauth.scope("address");
|
||||
oauth.clientId("test-app");
|
||||
OAuthClient.AccessTokenResponse response = browserLogin("password", "test-user@localhost", "password").tokenResponse;
|
||||
String accessToken = response.getAccessToken();
|
||||
System.out.println("accessToken:" + accessToken);
|
||||
assertAccessToken(oauth.verifyToken(accessToken), true, false);
|
||||
|
||||
oauth.clientId("resource-server");
|
||||
String tokenResponse = oauth.introspectAccessTokenWithClientCredential("resource-server", "password", accessToken);
|
||||
System.out.println("tokenResponse:" + tokenResponse);
|
||||
assertTokenIntrospectionResponse(JsonSerialization.readValue(tokenResponse, AccessToken.class), true, true, false);
|
||||
} finally {
|
||||
deleteProtocolMappers(protocolMappers);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessTokenTrueIntrospectionFalseTest() throws IOException {
|
||||
ProtocolMappersResource protocolMappers = setProtocolMappers(true, false, true);
|
||||
try {
|
||||
oauth.nonce("123456");
|
||||
oauth.scope("address");
|
||||
oauth.clientId("test-app");
|
||||
OAuthClient.AccessTokenResponse response = browserLogin("password", "test-user@localhost", "password").tokenResponse;
|
||||
String accessToken = response.getAccessToken();
|
||||
System.out.println("accessToken:" + accessToken);
|
||||
assertAccessToken(oauth.verifyToken(accessToken), true, true);
|
||||
|
||||
oauth.clientId("resource-server");
|
||||
String tokenResponse = oauth.introspectAccessTokenWithClientCredential("resource-server", "password", accessToken);
|
||||
System.out.println("tokenResponse:" + tokenResponse);
|
||||
// Most of the claims should not be included in introspectionResponse as introspectionMapper was disabled
|
||||
assertTokenIntrospectionResponse(JsonSerialization.readValue(tokenResponse, AccessToken.class), true, false, false);
|
||||
} finally {
|
||||
deleteProtocolMappers(protocolMappers);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accessTokenTrueIntrospectionTrueTest() throws IOException {
|
||||
ProtocolMappersResource protocolMappers = setProtocolMappers(true, true, true);
|
||||
try {
|
||||
oauth.nonce("123456");
|
||||
oauth.scope("address");
|
||||
oauth.clientId("test-app");
|
||||
OAuthClient.AccessTokenResponse response = browserLogin("password", "test-user@localhost", "password").tokenResponse;
|
||||
String accessToken = response.getAccessToken();
|
||||
System.out.println("accessToken:" + accessToken);
|
||||
assertAccessToken(oauth.verifyToken(accessToken), true, true);
|
||||
|
||||
oauth.clientId("resource-server");
|
||||
String tokenResponse = oauth.introspectAccessTokenWithClientCredential("resource-server", "password", accessToken);
|
||||
System.out.println("tokenResponse:" + tokenResponse);
|
||||
assertTokenIntrospectionResponse(JsonSerialization.readValue(tokenResponse, AccessToken.class), true, true, false);
|
||||
} finally {
|
||||
deleteProtocolMappers(protocolMappers);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void offlineTokenTest() throws IOException {
|
||||
ProtocolMappersResource protocolMappers = setProtocolMappers(false, true, true);
|
||||
try {
|
||||
oauth.nonce("123456");
|
||||
oauth.scope("openid address offline_access");
|
||||
|
||||
oauth.clientId("test-app");
|
||||
TokenResponseContext ctx = browserLogin("password", "test-user@localhost", "password");
|
||||
OAuthClient.AccessTokenResponse response = ctx.tokenResponse;
|
||||
String accessToken = response.getAccessToken();
|
||||
System.out.println("accessToken:" + accessToken);
|
||||
System.out.println("idtoken:" + response.getIdToken());
|
||||
assertAccessToken(oauth.verifyToken(accessToken), true, false);
|
||||
|
||||
oauth.clientId("resource-server");
|
||||
removeSession(ctx.userSessionId);
|
||||
String tokenResponse = oauth.introspectAccessTokenWithClientCredential("resource-server", "password", accessToken);
|
||||
System.out.println("tokenResponse:" + tokenResponse);
|
||||
assertTokenIntrospectionResponse(JsonSerialization.readValue(tokenResponse, AccessToken.class), true, true, false);
|
||||
} finally {
|
||||
deleteProtocolMappers(protocolMappers);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeSession(final String sessionId) {
|
||||
testingClient.testing().removeExpired("test");
|
||||
try {
|
||||
testingClient.testing().removeUserSession("test", sessionId);
|
||||
} catch (NotFoundException nfe) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clientCredentialTest() throws Exception {
|
||||
ProtocolMappersResource protocolMappers = setProtocolMappers(false, true, false);
|
||||
try {
|
||||
oauth.nonce("123456");
|
||||
oauth.scope("address");
|
||||
|
||||
oauth.clientId("test-app");
|
||||
OAuthClient.AccessTokenResponse response = oauth.doClientCredentialsGrantAccessTokenRequest("password");
|
||||
String accessToken = response.getAccessToken();
|
||||
System.out.println("accessToken:" + accessToken);
|
||||
assertAccessToken(oauth.verifyToken(accessToken), false, false);
|
||||
|
||||
oauth.clientId("resource-server");
|
||||
String tokenResponse = oauth.introspectAccessTokenWithClientCredential("resource-server", "password", accessToken);
|
||||
System.out.println("tokenResponse:" + tokenResponse);
|
||||
assertTokenIntrospectionResponse(JsonSerialization.readValue(tokenResponse, AccessToken.class), false);
|
||||
} finally {
|
||||
deleteProtocolMappers(protocolMappers);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exchangeTest() throws Exception {
|
||||
ProtocolMappersResource protocolMappers = setProtocolMappers(false, true, true);
|
||||
try {
|
||||
oauth.nonce("123456");
|
||||
oauth.scope("address");
|
||||
|
||||
oauth.clientId("test-app");
|
||||
OAuthClient.AccessTokenResponse response = browserLogin("password", "test-user@localhost", "password").tokenResponse;
|
||||
String accessToken = response.getAccessToken();
|
||||
System.out.println("accessToken:" + accessToken);
|
||||
assertAccessToken(oauth.verifyToken(accessToken), true, false);
|
||||
response = oauth.doTokenExchange(TEST, accessToken, null, "test-app", "password");
|
||||
String exchangedTokenString = response.getAccessToken();
|
||||
System.out.println("exchangedTokenString:" + exchangedTokenString);
|
||||
|
||||
oauth.clientId("resource-server");
|
||||
String tokenResponse = oauth.introspectAccessTokenWithClientCredential("resource-server", "password", exchangedTokenString);
|
||||
System.out.println("tokenResponse:" + tokenResponse);
|
||||
assertTokenIntrospectionResponse(JsonSerialization.readValue(tokenResponse, AccessToken.class), true, true, true);
|
||||
} finally {
|
||||
deleteProtocolMappers(protocolMappers);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertMapperClaims(AccessToken token, boolean isAddMapperResponseFlag, boolean isAuthCodeFlow) {
|
||||
if (isAddMapperResponseFlag) {
|
||||
if (isAuthCodeFlow) {
|
||||
Assert.assertNotNull(token.getName());
|
||||
Assert.assertNotNull(token.getGivenName());
|
||||
Assert.assertNotNull(token.getFamilyName());
|
||||
Assert.assertNotNull(token.getAddress());
|
||||
Assert.assertNotNull(token.getEmail());
|
||||
Assert.assertNotNull(token.getOtherClaims().get("user-session-note"));
|
||||
Assert.assertNotNull(token.getOtherClaims().get("test-claim"));
|
||||
Assert.assertNotNull(token.getOtherClaims().get("group-name"));
|
||||
}
|
||||
Assert.assertNotNull(token.getAudience());
|
||||
Assert.assertNotNull(token.getAcr());
|
||||
Assert.assertNotNull(token.getAllowedOrigins());
|
||||
Assert.assertNotNull(token.getRealmAccess());
|
||||
Assert.assertNotNull(token.getResourceAccess());
|
||||
Assert.assertNotNull(token.getEmailVerified());
|
||||
Assert.assertNotNull(token.getPreferredUsername());
|
||||
} else {
|
||||
if (isAuthCodeFlow) {
|
||||
Assert.assertTrue(token.getName() == null);
|
||||
Assert.assertTrue(token.getGivenName() == null);
|
||||
Assert.assertTrue(token.getFamilyName() == null);
|
||||
Assert.assertTrue(token.getAddress() == null);
|
||||
Assert.assertTrue(token.getEmail() == null);
|
||||
Assert.assertTrue(token.getOtherClaims().get("user-session-note") == null);
|
||||
Assert.assertTrue(token.getOtherClaims().get("test-claim") == null);
|
||||
Assert.assertTrue(token.getOtherClaims().get("group-name") == null);
|
||||
}
|
||||
Assert.assertTrue(token.getAcr() == null);
|
||||
Assert.assertTrue(token.getAllowedOrigins() == null);
|
||||
Assert.assertTrue(token.getRealmAccess() == null);
|
||||
Assert.assertTrue(token.getResourceAccess().isEmpty());
|
||||
Assert.assertTrue(token.getEmailVerified() == null);
|
||||
Assert.assertTrue(token.getPreferredUsername() == null);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertInitClaims(AccessToken token, boolean isAuthCodeFlow) {
|
||||
Assert.assertNotNull(token.getExp());
|
||||
Assert.assertNotNull(token.getIat());
|
||||
Assert.assertNotNull(token.getId());
|
||||
Assert.assertNotNull(token.getType());
|
||||
if (isAuthCodeFlow) {
|
||||
Assert.assertNotNull(token.getSessionId());
|
||||
Assert.assertNotNull(token.getAuth_time());
|
||||
} else {
|
||||
Assert.assertTrue(token.getSessionId() == null);
|
||||
Assert.assertTrue(token.getAuth_time() == null);
|
||||
}
|
||||
Assert.assertNotNull(token.getIssuedFor());
|
||||
Assert.assertNotNull(token.getScope());
|
||||
Assert.assertNotNull(token.getIssuer());
|
||||
}
|
||||
|
||||
private void assertIntrospectClaims(AccessToken token) {
|
||||
Assert.assertNotNull(token.getOtherClaims().get("client_id"));
|
||||
Assert.assertNotNull(token.getOtherClaims().get("active"));
|
||||
Assert.assertNotNull(token.getOtherClaims().get("token_type"));
|
||||
}
|
||||
|
||||
private void assertNonce(AccessToken token, boolean isAuthCodeFlow, boolean exchangeToken) {
|
||||
if (isAuthCodeFlow && !exchangeToken) {
|
||||
Assert.assertNotNull(token.getNonce());
|
||||
} else {
|
||||
Assert.assertTrue(token.getNonce() == null);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertAccessToken(AccessToken token, boolean isAuthCodeFlow, boolean isAddToAccessToken) {
|
||||
assertNonce(token, isAuthCodeFlow, false);
|
||||
assertMapperClaims(token, isAddToAccessToken, isAuthCodeFlow);
|
||||
assertInitClaims(token, isAuthCodeFlow);
|
||||
}
|
||||
|
||||
private void assertTokenIntrospectionResponse(AccessToken token, boolean isAuthCodeFlow) {
|
||||
assertTokenIntrospectionResponse(token, isAuthCodeFlow, true, false);
|
||||
}
|
||||
|
||||
private void assertTokenIntrospectionResponse(AccessToken token, boolean isAuthCodeFlow, boolean isAddToIntrospect, boolean exchangeToken) {
|
||||
assertNonce(token, isAuthCodeFlow, exchangeToken);
|
||||
assertMapperClaims(token, isAddToIntrospect, isAuthCodeFlow);
|
||||
assertInitClaims(token, isAuthCodeFlow);
|
||||
assertIntrospectClaims(token);
|
||||
}
|
||||
|
||||
protected RealmResource testRealm() {
|
||||
return adminClient.realm("test");
|
||||
}
|
||||
|
||||
private void setScopeProtocolMappers(boolean isIncludeAccessToken, boolean isIncludeIntrospection) {
|
||||
setScopeProtocolMapper(ACR_SCOPE, ACR, isIncludeAccessToken, isIncludeIntrospection);
|
||||
setScopeProtocolMapper(PROFILE_CLAIM, FULL_NAME, isIncludeAccessToken, isIncludeIntrospection);
|
||||
setScopeProtocolMapper(EMAIL, EMAIL, isIncludeAccessToken, isIncludeIntrospection);
|
||||
setScopeProtocolMapper(EMAIL, EMAIL_VERIFIED, isIncludeAccessToken, isIncludeIntrospection);
|
||||
setScopeProtocolMapper(PROFILE_CLAIM, GIVEN_NAME, isIncludeAccessToken, isIncludeIntrospection);
|
||||
setScopeProtocolMapper(PROFILE_CLAIM, FAMILY_NAME, isIncludeAccessToken, isIncludeIntrospection);
|
||||
setScopeProtocolMapper(PROFILE_CLAIM, USERNAME, isIncludeAccessToken, isIncludeIntrospection);
|
||||
setScopeProtocolMapper(WEB_ORIGINS_SCOPE, ALLOWED_WEB_ORIGINS, isIncludeAccessToken, isIncludeIntrospection);
|
||||
setScopeProtocolMapper(ROLES_SCOPE, REALM_ROLES, isIncludeAccessToken, isIncludeIntrospection);
|
||||
setScopeProtocolMapper(ROLES_SCOPE, CLIENT_ROLES, isIncludeAccessToken, isIncludeIntrospection);
|
||||
setScopeProtocolMapper(ROLES_SCOPE, AUDIENCE_RESOLVE, isIncludeAccessToken, isIncludeIntrospection);
|
||||
setScopeProtocolMapper(ADDRESS, ADDRESS, isIncludeAccessToken, isIncludeIntrospection);
|
||||
}
|
||||
|
||||
private void setScopeProtocolMapper(String scopeName, String mapperName, boolean isIncludeAccessToken, boolean isIncludeIntrospection) {
|
||||
ClientScopeResource scope = ApiUtil.findClientScopeByName(testRealm(), scopeName);
|
||||
ProtocolMapperRepresentation protocolMapper = ApiUtil.findProtocolMapperByName(scope, mapperName);
|
||||
Map<String, String> config = protocolMapper.getConfig();
|
||||
if (isIncludeAccessToken) {
|
||||
config.put(INCLUDE_IN_ACCESS_TOKEN, "true");
|
||||
} else {
|
||||
config.put(INCLUDE_IN_ACCESS_TOKEN, "false");
|
||||
}
|
||||
if (isIncludeIntrospection) {
|
||||
config.put(INCLUDE_IN_INTROSPECTION, "true");
|
||||
} else {
|
||||
config.put(INCLUDE_IN_INTROSPECTION, "false");
|
||||
}
|
||||
scope.getProtocolMappers().update(protocolMapper.getId(), protocolMapper);
|
||||
}
|
||||
|
||||
private ProtocolMappersResource setProtocolMappers(boolean isIncludeAccessToken, boolean isIncludeIntrospection, boolean setPairWise) {
|
||||
setScopeProtocolMappers(isIncludeAccessToken, isIncludeIntrospection);
|
||||
List<ProtocolMapperRepresentation> protocolMapperList = new ArrayList<>();
|
||||
setExistingProtocolMappers(protocolMapperList, isIncludeAccessToken, isIncludeIntrospection, setPairWise);
|
||||
ProtocolMappersResource protocolMappers = ApiUtil.findClientResourceByClientId(adminClient.realm("test"), "test-app").getProtocolMappers();
|
||||
protocolMappers.createMapper(protocolMapperList);
|
||||
return protocolMappers;
|
||||
}
|
||||
|
||||
private void setExistingProtocolMappers(List<ProtocolMapperRepresentation> protocolMapperList, boolean isIncludeAccessToken, boolean isIncludeIntrospection, boolean setPairWise) {
|
||||
Map<String, String> config = new HashMap<>();
|
||||
if (isIncludeAccessToken) {
|
||||
config.put(INCLUDE_IN_ACCESS_TOKEN, "true");
|
||||
} else {
|
||||
config.put(INCLUDE_IN_ACCESS_TOKEN, "false");
|
||||
}
|
||||
|
||||
if (isIncludeIntrospection) {
|
||||
config.put(INCLUDE_IN_INTROSPECTION, "true");
|
||||
} else {
|
||||
config.put(INCLUDE_IN_INTROSPECTION, "false");
|
||||
}
|
||||
|
||||
ProtocolMapperRepresentation audienceProtocolMapper = createClaimMapper("audience", AudienceProtocolMapper.PROVIDER_ID, new HashMap<>(config) {{
|
||||
put(INCLUDED_CLIENT_AUDIENCE, "account-console");
|
||||
}});
|
||||
protocolMapperList.add(audienceProtocolMapper);
|
||||
ProtocolMapperRepresentation roleNameMapper = createClaimMapper("role-name", RoleNameMapper.PROVIDER_ID, new HashMap<>(config) {{
|
||||
put(ROLE_CONFIG, "user");
|
||||
put(NEW_ROLE_NAME, "new-role");
|
||||
}});
|
||||
protocolMapperList.add(roleNameMapper);
|
||||
ProtocolMapperRepresentation groupMembershipMapper = createClaimMapper("group-member", GroupMembershipMapper.PROVIDER_ID, new HashMap<>(config) {{
|
||||
put(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, "group-name");
|
||||
}});
|
||||
protocolMapperList.add(groupMembershipMapper);
|
||||
ProtocolMapperRepresentation hardcodedClaim = createClaimMapper("hardcoded-claim", HardcodedClaim.PROVIDER_ID, new HashMap<>(config) {{
|
||||
put(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, "test-claim");
|
||||
put(CLAIM_VALUE, "test-value");
|
||||
}});
|
||||
protocolMapperList.add(hardcodedClaim);
|
||||
ProtocolMapperRepresentation hardcodedRole = createClaimMapper("hardcoded-role", HardcodedRole.PROVIDER_ID, new HashMap<>(config) {{
|
||||
put(ROLE_CONFIG, "hardcoded-role");
|
||||
}});
|
||||
protocolMapperList.add(hardcodedRole);
|
||||
ProtocolMapperRepresentation userSessionNoteMapper = createClaimMapper("user-session-note", UserSessionNoteMapper.PROVIDER_ID, new HashMap<>(config) {{
|
||||
put(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, "user-session-note");
|
||||
put(USER_SESSION_NOTE, "AUTH_TIME");
|
||||
}});
|
||||
protocolMapperList.add(userSessionNoteMapper);
|
||||
if (setPairWise) {
|
||||
ProtocolMapperRepresentation pairwiseSubMapper = createClaimMapper("pairwise-sub-mapper", "oidc-" + SHA256PairwiseSubMapper.PROVIDER_ID + PROVIDER_ID_SUFFIX, new HashMap<>(config) {{
|
||||
put(PAIRWISE_SUB_ALGORITHM_SALT, "abc");
|
||||
}});
|
||||
protocolMapperList.add(pairwiseSubMapper);
|
||||
}
|
||||
}
|
||||
|
||||
private static ProtocolMapperRepresentation createClaimMapper(String name, String providerId, Map<String, String> config) {
|
||||
ProtocolMapperModel mapper = new ProtocolMapperModel();
|
||||
mapper.setName(name);
|
||||
mapper.setProtocolMapper(providerId);
|
||||
mapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
|
||||
mapper.setConfig(config);
|
||||
return ModelToRepresentation.toRepresentation(mapper);
|
||||
}
|
||||
|
||||
private void deleteProtocolMappers(ProtocolMappersResource protocolMappers) {
|
||||
List<String> mapperNames = new ArrayList<>(Arrays.asList("reference", "audience", "role-name", "group-member", "hardcoded-claim", "hardcoded-role", "user-session-note", "pairwise-sub-mapper"));
|
||||
List<ProtocolMapperRepresentation> mappers = new ArrayList<>();
|
||||
for (String mapperName : mapperNames) {
|
||||
mappers.add(ProtocolMapperUtil.getMapperByNameAndProtocol(protocolMappers, OIDCLoginProtocol.LOGIN_PROTOCOL, mapperName));
|
||||
}
|
||||
|
||||
for (ProtocolMapperRepresentation mapper : mappers) {
|
||||
if (mapper != null) {
|
||||
protocolMappers.delete(mapper.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TokenResponseContext browserLogin(String clientSecret, String username, String password) {
|
||||
OAuthClient.AuthorizationEndpointResponse authsEndpointResponse = oauth.doLogin(username, password);
|
||||
String userSessionId = authsEndpointResponse.getSessionState();
|
||||
OAuthClient.AccessTokenResponse tokenResponse = oauth.doAccessTokenRequest(authsEndpointResponse.getCode(), clientSecret);
|
||||
return new TokenResponseContext(userSessionId, tokenResponse);
|
||||
}
|
||||
|
||||
private class TokenResponseContext {
|
||||
|
||||
private final String userSessionId;
|
||||
private final OAuthClient.AccessTokenResponse tokenResponse;
|
||||
|
||||
public TokenResponseContext(String userSessionId, OAuthClient.AccessTokenResponse tokenResponse) {
|
||||
this.userSessionId = userSessionId;
|
||||
this.tokenResponse = tokenResponse;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -92,7 +92,7 @@ public class DeployedScriptMapperTest extends AbstractTestRealmKeycloakTest {
|
|||
ClientResource app = findClientResourceByClientId(adminClient.realm("test"), "test-app");
|
||||
|
||||
ProtocolMapperRepresentation mapper = createScriptMapper("test-script-mapper1", "computed-via-script",
|
||||
"computed-via-script", "String", true, true, "'hello_' + user.username", false);
|
||||
"computed-via-script", "String", true, true, true, "'hello_' + user.username", false);
|
||||
|
||||
mapper.setProtocolMapper("script-mapper-a.js");
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ public class UndeployedScriptMapperNotAvailableTest extends AbstractTestRealmKey
|
|||
ClientResource app = findClientResourceByClientId(adminClient.realm("test"), "test-app");
|
||||
{
|
||||
ProtocolMapperRepresentation mapper = createScriptMapper("test-script-mapper1", "computed-via-script",
|
||||
"computed-via-script", "String", true, true, "'hello_' + user.username", false);
|
||||
"computed-via-script", "String", true, true, true, "'hello_' + user.username", false);
|
||||
|
||||
mapper.setProtocolMapper("script-mapper-a.js");
|
||||
|
||||
|
|
|
@ -47,8 +47,8 @@ public class ProtocolMapperUtil {
|
|||
* @param accessToken
|
||||
* @return
|
||||
*/
|
||||
public static ProtocolMapperRepresentation createAddressMapper(boolean idToken, boolean accessToken, boolean userInfo) {
|
||||
return ModelToRepresentation.toRepresentation(AddressMapper.createAddressMapper(idToken, accessToken, userInfo));
|
||||
public static ProtocolMapperRepresentation createAddressMapper(boolean idToken, boolean accessToken, boolean userInfo, boolean introspectionEndpoint) {
|
||||
return ModelToRepresentation.toRepresentation(AddressMapper.createAddressMapper(idToken, accessToken, userInfo, introspectionEndpoint));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,9 +65,9 @@ public class ProtocolMapperUtil {
|
|||
public static ProtocolMapperRepresentation createHardcodedClaim(String name,
|
||||
String hardcodedName,
|
||||
String hardcodedValue, String claimType,
|
||||
boolean accessToken, boolean idToken) {
|
||||
boolean accessToken, boolean idToken, boolean introspectionEndpoint) {
|
||||
return ModelToRepresentation.toRepresentation(HardcodedClaim.create(name, hardcodedName, hardcodedValue,
|
||||
claimType, accessToken, idToken));
|
||||
claimType, accessToken, idToken, introspectionEndpoint));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -85,64 +85,64 @@ public class ProtocolMapperUtil {
|
|||
public static ProtocolMapperRepresentation createClaimMapper(String name,
|
||||
String userAttribute,
|
||||
String tokenClaimName, String claimType,
|
||||
boolean accessToken, boolean idToken, boolean multivalued) {
|
||||
boolean accessToken, boolean idToken, boolean introspectionEndpoint, boolean multivalued) {
|
||||
return ModelToRepresentation.toRepresentation(UserAttributeMapper.createClaimMapper(name, userAttribute, tokenClaimName,
|
||||
claimType, accessToken, idToken, multivalued, false));
|
||||
claimType, accessToken, idToken, introspectionEndpoint, multivalued, false));
|
||||
|
||||
}
|
||||
|
||||
public static ProtocolMapperRepresentation createClaimMapper(String name,
|
||||
String userAttribute,
|
||||
String tokenClaimName, String claimType,
|
||||
boolean accessToken, boolean idToken,
|
||||
boolean accessToken, boolean idToken, boolean introspectionEndpoint,
|
||||
boolean multivalued, boolean aggregateAttrs) {
|
||||
return ModelToRepresentation.toRepresentation(UserAttributeMapper.createClaimMapper(name, userAttribute, tokenClaimName,
|
||||
claimType, accessToken, idToken, multivalued, aggregateAttrs));
|
||||
claimType, accessToken, idToken, introspectionEndpoint, multivalued, aggregateAttrs));
|
||||
|
||||
}
|
||||
|
||||
public static ProtocolMapperRepresentation createClaimMapper(String name,
|
||||
String userSessionNote,
|
||||
String tokenClaimName, String jsonType,
|
||||
boolean accessToken, boolean idToken) {
|
||||
boolean accessToken, boolean idToken, boolean introspectionEndpoint) {
|
||||
|
||||
return ModelToRepresentation.toRepresentation(UserSessionNoteMapper.createClaimMapper(name,
|
||||
userSessionNote,
|
||||
tokenClaimName, jsonType,
|
||||
accessToken, idToken));
|
||||
accessToken, idToken, introspectionEndpoint));
|
||||
}
|
||||
|
||||
|
||||
public static ProtocolMapperRepresentation createUserRealmRoleMappingMapper(String realmRolePrefix,
|
||||
String name,
|
||||
String tokenClaimName,
|
||||
boolean accessToken, boolean idToken) {
|
||||
boolean accessToken, boolean idToken, boolean introspectionEndpoint) {
|
||||
|
||||
return createUserRealmRoleMappingMapper(realmRolePrefix, name, tokenClaimName, accessToken, idToken, true);
|
||||
return createUserRealmRoleMappingMapper(realmRolePrefix, name, tokenClaimName, accessToken, idToken, introspectionEndpoint, true);
|
||||
}
|
||||
|
||||
public static ProtocolMapperRepresentation createUserRealmRoleMappingMapper(String realmRolePrefix,
|
||||
String name,
|
||||
String tokenClaimName,
|
||||
boolean accessToken, boolean idToken, boolean multiValued) {
|
||||
boolean accessToken, boolean idToken, boolean introspectionEndpoint, boolean multiValued) {
|
||||
|
||||
return ModelToRepresentation.toRepresentation(UserRealmRoleMappingMapper.create(realmRolePrefix, name, tokenClaimName, accessToken, idToken, multiValued));
|
||||
return ModelToRepresentation.toRepresentation(UserRealmRoleMappingMapper.create(realmRolePrefix, name, tokenClaimName, accessToken, idToken, introspectionEndpoint, multiValued));
|
||||
}
|
||||
|
||||
public static ProtocolMapperRepresentation createUserClientRoleMappingMapper(String clientId, String clientRolePrefix,
|
||||
String name,
|
||||
String tokenClaimName,
|
||||
boolean accessToken, boolean idToken) {
|
||||
boolean accessToken, boolean idToken, boolean introspectionEndpoint) {
|
||||
|
||||
return createUserClientRoleMappingMapper(clientId, clientRolePrefix, name, tokenClaimName, accessToken, idToken, true);
|
||||
return createUserClientRoleMappingMapper(clientId, clientRolePrefix, name, tokenClaimName, accessToken, idToken, introspectionEndpoint, true);
|
||||
}
|
||||
|
||||
public static ProtocolMapperRepresentation createUserClientRoleMappingMapper(String clientId, String clientRolePrefix,
|
||||
String name,
|
||||
String tokenClaimName,
|
||||
boolean accessToken, boolean idToken, boolean multiValued) {
|
||||
boolean accessToken, boolean idToken, boolean introspectionEndpoint, boolean multiValued) {
|
||||
|
||||
return ModelToRepresentation.toRepresentation(UserClientRoleMappingMapper.create(clientId, clientRolePrefix, name, tokenClaimName, accessToken, idToken, multiValued));
|
||||
return ModelToRepresentation.toRepresentation(UserClientRoleMappingMapper.create(clientId, clientRolePrefix, name, tokenClaimName, accessToken, idToken, introspectionEndpoint, multiValued));
|
||||
}
|
||||
|
||||
public static ProtocolMapperRepresentation getMapperByNameAndProtocol(ProtocolMappersResource protocolMappers, String protocol, String name) {
|
||||
|
@ -160,11 +160,12 @@ public class ProtocolMapperUtil {
|
|||
String claimType,
|
||||
boolean accessToken,
|
||||
boolean idToken,
|
||||
boolean introspectionEndpoint,
|
||||
String script,
|
||||
boolean multiValued) {
|
||||
|
||||
return ModelToRepresentation.toRepresentation(
|
||||
ScriptBasedOIDCProtocolMapper.create(name, userAttribute, tokenClaimName, claimType, accessToken, idToken, script, multiValued)
|
||||
ScriptBasedOIDCProtocolMapper.create(name, userAttribute, tokenClaimName, claimType, accessToken, idToken, introspectionEndpoint, script, multiValued)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -175,10 +176,10 @@ public class ProtocolMapperUtil {
|
|||
public static ProtocolMapperRepresentation createAudienceMapper(String name,
|
||||
String includedClientAudience,
|
||||
String includedCustomAudience,
|
||||
boolean accessToken, boolean idToken) {
|
||||
boolean accessToken, boolean idToken, boolean introspectionEndpoint) {
|
||||
|
||||
return ModelToRepresentation.toRepresentation(
|
||||
AudienceProtocolMapper.createClaimMapper(name, includedClientAudience, includedCustomAudience, accessToken, idToken)
|
||||
AudienceProtocolMapper.createClaimMapper(name, includedClientAudience, includedCustomAudience, accessToken, idToken, introspectionEndpoint)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue