use of org.keycloak.representations.AccessTokenResponse in project keycloak by keycloak.
the class DefaultTokenExchangeProvider method exchangeClientToOIDCClient.
protected Response exchangeClientToOIDCClient(UserModel targetUser, UserSessionModel targetUserSession, String requestedTokenType, ClientModel targetClient, String audience, String scope) {
RootAuthenticationSessionModel rootAuthSession = new AuthenticationSessionManager(session).createAuthenticationSession(realm, false);
AuthenticationSessionModel authSession = rootAuthSession.createAuthenticationSession(targetClient);
authSession.setAuthenticatedUser(targetUser);
authSession.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
authSession.setClientNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(session.getContext().getUri().getBaseUri(), realm.getName()));
authSession.setClientNote(OIDCLoginProtocol.SCOPE_PARAM, scope);
event.session(targetUserSession);
AuthenticationManager.setClientScopesInSession(authSession);
ClientSessionContext clientSessionCtx = TokenManager.attachAuthenticationSession(this.session, targetUserSession, authSession);
updateUserSessionFromClientAuth(targetUserSession);
TokenManager.AccessTokenResponseBuilder responseBuilder = tokenManager.responseBuilder(realm, targetClient, event, this.session, targetUserSession, clientSessionCtx).generateAccessToken();
responseBuilder.getAccessToken().issuedFor(client.getClientId());
if (audience != null) {
responseBuilder.getAccessToken().addAudience(audience);
}
if (requestedTokenType.equals(OAuth2Constants.REFRESH_TOKEN_TYPE) && OIDCAdvancedConfigWrapper.fromClientModel(client).isUseRefreshToken()) {
responseBuilder.generateRefreshToken();
responseBuilder.getRefreshToken().issuedFor(client.getClientId());
}
String scopeParam = clientSessionCtx.getClientSession().getNote(OAuth2Constants.SCOPE);
if (TokenUtil.isOIDCRequest(scopeParam)) {
responseBuilder.generateIDToken().generateAccessTokenHash();
}
AccessTokenResponse res = responseBuilder.build();
event.detail(Details.AUDIENCE, targetClient.getClientId());
event.success();
return cors.builder(Response.ok(res, MediaType.APPLICATION_JSON_TYPE)).build();
}
use of org.keycloak.representations.AccessTokenResponse in project keycloak by keycloak.
the class OIDCLoginProtocol method authenticated.
@Override
public Response authenticated(AuthenticationSessionModel authSession, UserSessionModel userSession, ClientSessionContext clientSessionCtx) {
AuthenticatedClientSessionModel clientSession = clientSessionCtx.getClientSession();
if (isOAuth2DeviceVerificationFlow(authSession)) {
return approveOAuth2DeviceAuthorization(authSession, clientSession, session);
}
String responseTypeParam = authSession.getClientNote(OIDCLoginProtocol.RESPONSE_TYPE_PARAM);
String responseModeParam = authSession.getClientNote(OIDCLoginProtocol.RESPONSE_MODE_PARAM);
setupResponseTypeAndMode(responseTypeParam, responseModeParam);
String redirect = authSession.getRedirectUri();
OIDCRedirectUriBuilder redirectUri = OIDCRedirectUriBuilder.fromUri(redirect, responseMode, session, clientSession);
String state = authSession.getClientNote(OIDCLoginProtocol.STATE_PARAM);
logger.debugv("redirectAccessCode: state: {0}", state);
if (state != null)
redirectUri.addParam(OAuth2Constants.STATE, state);
OIDCAdvancedConfigWrapper clientConfig = OIDCAdvancedConfigWrapper.fromClientModel(clientSession.getClient());
if (!clientConfig.isExcludeSessionStateFromAuthResponse()) {
redirectUri.addParam(OAuth2Constants.SESSION_STATE, userSession.getId());
}
String nonce = authSession.getClientNote(OIDCLoginProtocol.NONCE_PARAM);
clientSessionCtx.setAttribute(OIDCLoginProtocol.NONCE_PARAM, nonce);
String kcActionStatus = authSession.getClientNote(Constants.KC_ACTION_STATUS);
if (kcActionStatus != null) {
redirectUri.addParam(Constants.KC_ACTION_STATUS, kcActionStatus);
}
// Standard or hybrid flow
String code = null;
if (responseType.hasResponseType(OIDCResponseType.CODE)) {
OAuth2Code codeData = new OAuth2Code(UUID.randomUUID(), Time.currentTime() + userSession.getRealm().getAccessCodeLifespan(), nonce, authSession.getClientNote(OAuth2Constants.SCOPE), authSession.getClientNote(OIDCLoginProtocol.REDIRECT_URI_PARAM), authSession.getClientNote(OIDCLoginProtocol.CODE_CHALLENGE_PARAM), authSession.getClientNote(OIDCLoginProtocol.CODE_CHALLENGE_METHOD_PARAM));
code = OAuth2CodeParser.persistCode(session, clientSession, codeData);
redirectUri.addParam(OAuth2Constants.CODE, code);
}
// Implicit or hybrid flow
if (responseType.isImplicitOrHybridFlow()) {
org.keycloak.protocol.oidc.TokenManager tokenManager = new org.keycloak.protocol.oidc.TokenManager();
org.keycloak.protocol.oidc.TokenManager.AccessTokenResponseBuilder responseBuilder = tokenManager.responseBuilder(realm, clientSession.getClient(), event, session, userSession, clientSessionCtx).generateAccessToken();
if (responseType.hasResponseType(OIDCResponseType.ID_TOKEN)) {
responseBuilder.generateIDToken(isIdTokenAsDetachedSignature(clientSession.getClient()));
if (responseType.hasResponseType(OIDCResponseType.TOKEN)) {
responseBuilder.generateAccessTokenHash();
}
if (responseType.hasResponseType(OIDCResponseType.CODE)) {
responseBuilder.generateCodeHash(code);
}
// http://openid.net/specs/openid-financial-api-part-2.html#authorization-server
if (state != null && !state.isEmpty())
responseBuilder.generateStateHash(state);
}
AccessTokenResponse res = responseBuilder.build();
if (responseType.hasResponseType(OIDCResponseType.ID_TOKEN)) {
redirectUri.addParam(OAuth2Constants.ID_TOKEN, res.getIdToken());
}
if (responseType.hasResponseType(OIDCResponseType.TOKEN)) {
redirectUri.addParam(OAuth2Constants.ACCESS_TOKEN, res.getToken());
redirectUri.addParam(OAuth2Constants.TOKEN_TYPE, res.getTokenType());
redirectUri.addParam(OAuth2Constants.EXPIRES_IN, String.valueOf(res.getExpiresIn()));
}
}
return redirectUri.build();
}
use of org.keycloak.representations.AccessTokenResponse in project keycloak by keycloak.
the class AuthUtil method ensureToken.
public static String ensureToken(ConfigData config) {
checkAuthInfo(config);
RealmConfigData realmConfig = config.sessionRealmConfigData();
long now = currentTimeMillis();
// if it's less than 5s to expiry, renew it
if (realmConfig.getExpiresAt() - now < 5000) {
// if it's less than 5s to expiry, fail with credentials expired
if (realmConfig.getRefreshExpiresAt() != null && realmConfig.getRefreshExpiresAt() - now < 5000) {
throw new RuntimeException("Session has expired. Login again with '" + OsUtil.CMD + " config credentials'");
}
if (realmConfig.getSigExpiresAt() != null && realmConfig.getSigExpiresAt() - now < 5000) {
throw new RuntimeException("Session has expired. Login again with '" + OsUtil.CMD + " config credentials'");
}
try {
String authorization = null;
StringBuilder body = new StringBuilder();
if (realmConfig.getRefreshToken() != null) {
body.append("grant_type=refresh_token").append("&refresh_token=").append(realmConfig.getRefreshToken());
} else {
body.append("grant_type=").append(realmConfig.getGrantTypeForAuthentication());
}
body.append("&client_id=").append(urlencode(realmConfig.getClientId()));
if (realmConfig.getSigningToken() != null) {
body.append("&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer").append("&client_assertion=").append(realmConfig.getSigningToken());
} else if (realmConfig.getSecret() != null) {
authorization = BasicAuthHelper.createHeader(realmConfig.getClientId(), realmConfig.getSecret());
}
InputStream result = doPost(realmConfig.serverUrl() + "/realms/" + realmConfig.realm() + "/protocol/openid-connect/token", APPLICATION_FORM_URL_ENCODED, APPLICATION_JSON, body.toString(), authorization);
AccessTokenResponse token = JsonSerialization.readValue(result, AccessTokenResponse.class);
saveMergeConfig(cfg -> {
RealmConfigData realmData = cfg.sessionRealmConfigData();
realmData.setToken(token.getToken());
realmData.setRefreshToken(token.getRefreshToken());
realmData.setExpiresAt(currentTimeMillis() + token.getExpiresIn() * 1000);
if (token.getRefreshToken() != null) {
realmData.setRefreshExpiresAt(currentTimeMillis() + token.getRefreshExpiresIn() * 1000);
}
});
return token.getToken();
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Unexpected error", e);
} catch (IOException e) {
throw new RuntimeException("Failed to read Refresh Token response", e);
}
}
return realmConfig.getToken();
}
use of org.keycloak.representations.AccessTokenResponse in project keycloak by keycloak.
the class SocialLoginTest method testTokenExchange.
protected void testTokenExchange() {
List<UserRepresentation> users = adminClient.realm(REALM).users().search(null, null, null);
Assert.assertEquals(1, users.size());
String username = users.get(0).getUsername();
checkFeature(501, username);
Response tokenResp = testingClient.testing().enableFeature(Profile.Feature.TOKEN_EXCHANGE.toString());
assertEquals(200, tokenResp.getStatus());
ProfileAssume.assumeFeatureEnabled(Profile.Feature.TOKEN_EXCHANGE);
Client httpClient = AdminClientUtil.createResteasyClient();
try {
AccessTokenResponse tokenResponse = checkFeature(200, username);
Assert.assertNotNull(tokenResponse);
String socialToken = tokenResponse.getToken();
Assert.assertNotNull(socialToken);
// remove all users
removeUser();
users = adminClient.realm(REALM).users().search(null, null, null);
Assert.assertEquals(0, users.size());
// now try external exchange where we trust social provider and import the external token.
Response response = getExchangeUrl(httpClient).request().header(HttpHeaders.AUTHORIZATION, BasicAuthHelper.createHeader(EXCHANGE_CLIENT, "secret")).post(Entity.form(new Form().param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.TOKEN_EXCHANGE_GRANT_TYPE).param(OAuth2Constants.SUBJECT_TOKEN, socialToken).param(OAuth2Constants.SUBJECT_TOKEN_TYPE, OAuth2Constants.ACCESS_TOKEN_TYPE).param(OAuth2Constants.SUBJECT_ISSUER, currentTestProvider.id())));
Assert.assertEquals(200, response.getStatus());
response.close();
users = adminClient.realm(REALM).users().search(null, null, null);
Assert.assertEquals(1, users.size());
Assert.assertEquals(username, users.get(0).getUsername());
// remove all users
removeUser();
users = adminClient.realm(REALM).users().search(null, null, null);
Assert.assertEquals(0, users.size());
// /// Test that we can update social token from session with stored tokens turned off.
// turn off store token
IdentityProviderRepresentation idp = adminClient.realm(REALM).identityProviders().get(currentTestProvider.id).toRepresentation();
idp.setStoreToken(false);
adminClient.realm(REALM).identityProviders().get(idp.getAlias()).update(idp);
// first exchange social token to get a user session that should store the social token there
response = getExchangeUrl(httpClient).request().header(HttpHeaders.AUTHORIZATION, BasicAuthHelper.createHeader(EXCHANGE_CLIENT, "secret")).post(Entity.form(new Form().param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.TOKEN_EXCHANGE_GRANT_TYPE).param(OAuth2Constants.SUBJECT_TOKEN, socialToken).param(OAuth2Constants.SUBJECT_TOKEN_TYPE, OAuth2Constants.ACCESS_TOKEN_TYPE).param(OAuth2Constants.SUBJECT_ISSUER, currentTestProvider.id())));
Assert.assertEquals(200, response.getStatus());
tokenResponse = response.readEntity(AccessTokenResponse.class);
String keycloakToken = tokenResponse.getToken();
response.close();
// now take keycloak token and make sure it can get back the social token from the user session since stored tokens are off
response = getExchangeUrl(httpClient).request().header(HttpHeaders.AUTHORIZATION, BasicAuthHelper.createHeader(EXCHANGE_CLIENT, "secret")).post(Entity.form(new Form().param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.TOKEN_EXCHANGE_GRANT_TYPE).param(OAuth2Constants.SUBJECT_TOKEN, keycloakToken).param(OAuth2Constants.SUBJECT_TOKEN_TYPE, OAuth2Constants.ACCESS_TOKEN_TYPE).param(OAuth2Constants.REQUESTED_TOKEN_TYPE, OAuth2Constants.ACCESS_TOKEN_TYPE).param(OAuth2Constants.REQUESTED_ISSUER, currentTestProvider.id())));
Assert.assertEquals(200, response.getStatus());
tokenResponse = response.readEntity(AccessTokenResponse.class);
response.close();
Assert.assertEquals(socialToken, tokenResponse.getToken());
// turn on store token
idp = adminClient.realm(REALM).identityProviders().get(currentTestProvider.id).toRepresentation();
idp.setStoreToken(true);
adminClient.realm(REALM).identityProviders().get(idp.getAlias()).update(idp);
} finally {
httpClient.close();
tokenResp = testingClient.testing().disableFeature(Profile.Feature.TOKEN_EXCHANGE.toString());
assertEquals(200, tokenResp.getStatus());
checkFeature(501, username);
}
}
use of org.keycloak.representations.AccessTokenResponse in project keycloak by keycloak.
the class SocialLoginTest method checkFeature.
private AccessTokenResponse checkFeature(int expectedStatusCode, String username) {
Client httpClient = AdminClientUtil.createResteasyClient();
Response response = null;
try {
testingClient.server().run(SocialLoginTest::setupClientExchangePermissions);
WebTarget exchangeUrl = getExchangeUrl(httpClient);
response = exchangeUrl.request().header(HttpHeaders.AUTHORIZATION, BasicAuthHelper.createHeader(EXCHANGE_CLIENT, "secret")).post(Entity.form(new Form().param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.TOKEN_EXCHANGE_GRANT_TYPE).param(OAuth2Constants.REQUESTED_SUBJECT, username).param(OAuth2Constants.REQUESTED_TOKEN_TYPE, OAuth2Constants.ACCESS_TOKEN_TYPE).param(OAuth2Constants.REQUESTED_ISSUER, currentTestProvider.id())));
Assert.assertEquals(expectedStatusCode, response.getStatus());
if (expectedStatusCode == Response.Status.OK.getStatusCode())
return response.readEntity(AccessTokenResponse.class);
else
return null;
} finally {
if (response != null)
response.close();
httpClient.close();
}
}
Aggregations