ID token mapping
This commit is contained in:
parent
51e2507f5d
commit
453ef808cc
3 changed files with 43 additions and 39 deletions
|
@ -339,7 +339,7 @@ public class OIDCLoginProtocolService {
|
||||||
|
|
||||||
TokenManager.attachClientSession(userSession, clientSession);
|
TokenManager.attachClientSession(userSession, clientSession);
|
||||||
|
|
||||||
AccessTokenResponse res = tokenManager.responseBuilder(realm, client, event)
|
AccessTokenResponse res = tokenManager.responseBuilder(realm, client, event, session, userSession, clientSession)
|
||||||
.generateAccessToken(session, scope, client, user, userSession, clientSession)
|
.generateAccessToken(session, scope, client, user, userSession, clientSession)
|
||||||
.generateRefreshToken()
|
.generateRefreshToken()
|
||||||
.generateIDToken()
|
.generateIDToken()
|
||||||
|
@ -506,9 +506,9 @@ public class OIDCLoginProtocolService {
|
||||||
event.error(Errors.INVALID_TOKEN);
|
event.error(Errors.INVALID_TOKEN);
|
||||||
return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
|
return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
|
||||||
}
|
}
|
||||||
AccessToken accessToken;
|
AccessTokenResponse res;
|
||||||
try {
|
try {
|
||||||
accessToken = tokenManager.refreshAccessToken(session, uriInfo, clientConnection, realm, client, refreshToken, event);
|
res = tokenManager.refreshAccessToken(session, uriInfo, clientConnection, realm, client, refreshToken, event);
|
||||||
} catch (OAuthErrorException e) {
|
} catch (OAuthErrorException e) {
|
||||||
Map<String, String> error = new HashMap<String, String>();
|
Map<String, String> error = new HashMap<String, String>();
|
||||||
error.put(OAuth2Constants.ERROR, e.getError());
|
error.put(OAuth2Constants.ERROR, e.getError());
|
||||||
|
@ -517,10 +517,6 @@ public class OIDCLoginProtocolService {
|
||||||
return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
|
return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
|
||||||
}
|
}
|
||||||
|
|
||||||
AccessTokenResponse res = tokenManager.responseBuilder(realm, client, event)
|
|
||||||
.accessToken(accessToken)
|
|
||||||
.generateIDToken()
|
|
||||||
.generateRefreshToken().build();
|
|
||||||
|
|
||||||
event.success();
|
event.success();
|
||||||
|
|
||||||
|
@ -680,7 +676,7 @@ public class OIDCLoginProtocolService {
|
||||||
return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
|
return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
|
||||||
}
|
}
|
||||||
|
|
||||||
AccessTokenResponse res = tokenManager.responseBuilder(realm, client, event)
|
AccessTokenResponse res = tokenManager.responseBuilder(realm, client, event, session, userSession, clientSession)
|
||||||
.accessToken(token)
|
.accessToken(token)
|
||||||
.generateIDToken()
|
.generateIDToken()
|
||||||
.generateRefreshToken().build();
|
.generateRefreshToken().build();
|
||||||
|
|
|
@ -22,6 +22,7 @@ import org.keycloak.models.UserSessionProvider;
|
||||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.protocol.ProtocolMapper;
|
import org.keycloak.protocol.ProtocolMapper;
|
||||||
import org.keycloak.protocol.oidc.mappers.OIDCAccessTokenMapper;
|
import org.keycloak.protocol.oidc.mappers.OIDCAccessTokenMapper;
|
||||||
|
import org.keycloak.protocol.oidc.mappers.OIDCIDTokenMapper;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
import org.keycloak.representations.AccessTokenResponse;
|
import org.keycloak.representations.AccessTokenResponse;
|
||||||
import org.keycloak.representations.IDToken;
|
import org.keycloak.representations.IDToken;
|
||||||
|
@ -58,7 +59,7 @@ public class TokenManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public AccessToken refreshAccessToken(KeycloakSession session, UriInfo uriInfo, ClientConnection connection, RealmModel realm, ClientModel client, String encodedRefreshToken, EventBuilder event) throws OAuthErrorException {
|
public AccessTokenResponse refreshAccessToken(KeycloakSession session, UriInfo uriInfo, ClientConnection connection, RealmModel realm, ClientModel client, String encodedRefreshToken, EventBuilder event) throws OAuthErrorException {
|
||||||
RefreshToken refreshToken = verifyRefreshToken(realm, encodedRefreshToken);
|
RefreshToken refreshToken = verifyRefreshToken(realm, encodedRefreshToken);
|
||||||
|
|
||||||
event.user(refreshToken.getSubject()).session(refreshToken.getSessionState()).detail(Details.REFRESH_TOKEN_ID, refreshToken.getId());
|
event.user(refreshToken.getSubject()).session(refreshToken.getSessionState()).detail(Details.REFRESH_TOKEN_ID, refreshToken.getId());
|
||||||
|
@ -105,11 +106,15 @@ public class TokenManager {
|
||||||
AccessToken accessToken = initToken(realm, client, user, userSession, clientSession);
|
AccessToken accessToken = initToken(realm, client, user, userSession, clientSession);
|
||||||
accessToken.setRealmAccess(refreshToken.getRealmAccess());
|
accessToken.setRealmAccess(refreshToken.getRealmAccess());
|
||||||
accessToken.setResourceAccess(refreshToken.getResourceAccess());
|
accessToken.setResourceAccess(refreshToken.getResourceAccess());
|
||||||
accessToken = transformToken(session, accessToken, realm, client, user, userSession, clientSession);
|
accessToken = transformAccessToken(session, accessToken, realm, client, user, userSession, clientSession);
|
||||||
|
|
||||||
userSession.setLastSessionRefresh(currentTime);
|
userSession.setLastSessionRefresh(currentTime);
|
||||||
|
|
||||||
return accessToken;
|
AccessTokenResponse res = responseBuilder(realm, client, event, session, userSession, clientSession)
|
||||||
|
.accessToken(accessToken)
|
||||||
|
.generateIDToken()
|
||||||
|
.generateRefreshToken().build();
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RefreshToken verifyRefreshToken(RealmModel realm, String encodedRefreshToken) throws OAuthErrorException {
|
public RefreshToken verifyRefreshToken(RealmModel realm, String encodedRefreshToken) throws OAuthErrorException {
|
||||||
|
@ -138,7 +143,7 @@ public class TokenManager {
|
||||||
for (RoleModel role : requestedRoles) {
|
for (RoleModel role : requestedRoles) {
|
||||||
addComposites(token, role);
|
addComposites(token, role);
|
||||||
}
|
}
|
||||||
token = transformToken(session, token, realm, client, user, userSession, clientSession);
|
token = transformAccessToken(session, token, realm, client, user, userSession, clientSession);
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,8 +238,8 @@ public class TokenManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public AccessToken transformToken(KeycloakSession session, AccessToken token, RealmModel realm, ClientModel client, UserModel user,
|
public AccessToken transformAccessToken(KeycloakSession session, AccessToken token, RealmModel realm, ClientModel client, UserModel user,
|
||||||
UserSessionModel userSession, ClientSessionModel clientSession) {
|
UserSessionModel userSession, ClientSessionModel clientSession) {
|
||||||
Set<ProtocolMapperModel> mappings = client.getProtocolMappers();
|
Set<ProtocolMapperModel> mappings = client.getProtocolMappers();
|
||||||
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
||||||
for (ProtocolMapperModel mapping : mappings) {
|
for (ProtocolMapperModel mapping : mappings) {
|
||||||
|
@ -249,6 +254,21 @@ public class TokenManager {
|
||||||
}
|
}
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
public void transformIDToken(KeycloakSession session, IDToken token, RealmModel realm, ClientModel client, UserModel user,
|
||||||
|
UserSessionModel userSession, ClientSessionModel clientSession) {
|
||||||
|
Set<ProtocolMapperModel> mappings = client.getProtocolMappers();
|
||||||
|
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
||||||
|
for (ProtocolMapperModel mapping : mappings) {
|
||||||
|
if (!mapping.getProtocol().equals(OIDCLoginProtocol.LOGIN_PROTOCOL)) continue;
|
||||||
|
|
||||||
|
ProtocolMapper mapper = (ProtocolMapper)sessionFactory.getProviderFactory(ProtocolMapper.class, mapping.getProtocolMapper());
|
||||||
|
if (mapper == null || !(mapper instanceof OIDCIDTokenMapper)) continue;
|
||||||
|
token = ((OIDCIDTokenMapper)mapper).transformIDToken(token, mapping, session, userSession, clientSession);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected AccessToken initToken(RealmModel realm, ClientModel client, UserModel user, UserSessionModel session, ClientSessionModel clientSession) {
|
protected AccessToken initToken(RealmModel realm, ClientModel client, UserModel user, UserSessionModel session, ClientSessionModel clientSession) {
|
||||||
|
@ -308,22 +328,29 @@ public class TokenManager {
|
||||||
return encodedToken;
|
return encodedToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AccessTokenResponseBuilder responseBuilder(RealmModel realm, ClientModel client, EventBuilder event) {
|
public AccessTokenResponseBuilder responseBuilder(RealmModel realm, ClientModel client, EventBuilder event, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) {
|
||||||
return new AccessTokenResponseBuilder(realm, client, event);
|
return new AccessTokenResponseBuilder(realm, client, event, session, userSession, clientSession);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AccessTokenResponseBuilder {
|
public class AccessTokenResponseBuilder {
|
||||||
RealmModel realm;
|
RealmModel realm;
|
||||||
ClientModel client;
|
ClientModel client;
|
||||||
|
EventBuilder event;
|
||||||
|
KeycloakSession session;
|
||||||
|
UserSessionModel userSession;
|
||||||
|
ClientSessionModel clientSession;
|
||||||
|
|
||||||
AccessToken accessToken;
|
AccessToken accessToken;
|
||||||
RefreshToken refreshToken;
|
RefreshToken refreshToken;
|
||||||
IDToken idToken;
|
IDToken idToken;
|
||||||
EventBuilder event;
|
|
||||||
|
|
||||||
public AccessTokenResponseBuilder(RealmModel realm, ClientModel client, EventBuilder event) {
|
public AccessTokenResponseBuilder(RealmModel realm, ClientModel client, EventBuilder event, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) {
|
||||||
this.realm = realm;
|
this.realm = realm;
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.event = event;
|
this.event = event;
|
||||||
|
this.session = session;
|
||||||
|
this.userSession = userSession;
|
||||||
|
this.clientSession = clientSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AccessTokenResponseBuilder accessToken(AccessToken accessToken) {
|
public AccessTokenResponseBuilder accessToken(AccessToken accessToken) {
|
||||||
|
@ -366,25 +393,7 @@ public class TokenManager {
|
||||||
if (realm.getAccessTokenLifespan() > 0) {
|
if (realm.getAccessTokenLifespan() > 0) {
|
||||||
idToken.expiration(Time.currentTime() + realm.getAccessTokenLifespan());
|
idToken.expiration(Time.currentTime() + realm.getAccessTokenLifespan());
|
||||||
}
|
}
|
||||||
idToken.getUserClaimSet().setPreferredUsername(accessToken.getUserClaimSet().getPreferredUsername());
|
transformIDToken(session, idToken, realm, client, userSession.getUser(), userSession, clientSession);
|
||||||
idToken.getUserClaimSet().setGivenName(accessToken.getUserClaimSet().getGivenName());
|
|
||||||
idToken.getUserClaimSet().setMiddleName(accessToken.getUserClaimSet().getMiddleName());
|
|
||||||
idToken.getUserClaimSet().setFamilyName(accessToken.getUserClaimSet().getFamilyName());
|
|
||||||
idToken.getUserClaimSet().setName(accessToken.getUserClaimSet().getName());
|
|
||||||
idToken.getUserClaimSet().setNickName(accessToken.getUserClaimSet().getNickName());
|
|
||||||
idToken.getUserClaimSet().setGender(accessToken.getUserClaimSet().getGender());
|
|
||||||
idToken.getUserClaimSet().setPicture(accessToken.getUserClaimSet().getPicture());
|
|
||||||
idToken.getUserClaimSet().setProfile(accessToken.getUserClaimSet().getProfile());
|
|
||||||
idToken.getUserClaimSet().setWebsite(accessToken.getUserClaimSet().getWebsite());
|
|
||||||
idToken.getUserClaimSet().setBirthdate(accessToken.getUserClaimSet().getBirthdate());
|
|
||||||
idToken.getUserClaimSet().setEmail(accessToken.getUserClaimSet().getEmail());
|
|
||||||
idToken.getUserClaimSet().setEmailVerified(accessToken.getUserClaimSet().getEmailVerified());
|
|
||||||
idToken.getUserClaimSet().setLocale(accessToken.getUserClaimSet().getLocale());
|
|
||||||
idToken.getUserClaimSet().setAddress(accessToken.getUserClaimSet().getAddress());
|
|
||||||
idToken.getUserClaimSet().setPhoneNumber(accessToken.getUserClaimSet().getPhoneNumber());
|
|
||||||
idToken.getUserClaimSet().setPhoneNumberVerified(accessToken.getUserClaimSet().getPhoneNumberVerified());
|
|
||||||
idToken.getUserClaimSet().setZoneinfo(accessToken.getUserClaimSet().getZoneinfo());
|
|
||||||
idToken.setOtherClaims(accessToken.getOtherClaims());
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,6 @@ import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.UserSessionModel;
|
import org.keycloak.models.UserSessionModel;
|
||||||
import org.keycloak.representations.AccessToken;
|
import org.keycloak.representations.AccessToken;
|
||||||
import org.keycloak.representations.UserClaimSet;
|
|
||||||
import org.keycloak.services.managers.AppAuthManager;
|
import org.keycloak.services.managers.AppAuthManager;
|
||||||
import org.keycloak.services.managers.EventsManager;
|
import org.keycloak.services.managers.EventsManager;
|
||||||
import org.keycloak.services.resources.Cors;
|
import org.keycloak.services.resources.Cors;
|
||||||
|
@ -133,7 +132,7 @@ public class UserInfoService {
|
||||||
ClientModel clientModel = realmModel.findClient(accessToken.getIssuedFor());
|
ClientModel clientModel = realmModel.findClient(accessToken.getIssuedFor());
|
||||||
UserModel userModel = userSession.getUser();
|
UserModel userModel = userSession.getUser();
|
||||||
AccessToken userInfo = new AccessToken();
|
AccessToken userInfo = new AccessToken();
|
||||||
this.tokenManager.transformToken(session, userInfo, realmModel, clientModel, userModel, userSession, null);
|
this.tokenManager.transformAccessToken(session, userInfo, realmModel, clientModel, userModel, userSession, null);
|
||||||
|
|
||||||
event
|
event
|
||||||
.detail(Details.USERNAME, userModel.getUsername())
|
.detail(Details.USERNAME, userModel.getUsername())
|
||||||
|
|
Loading…
Reference in a new issue