/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.util;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.junit.Assert;
import org.keycloak.OAuth2Constants;
import org.keycloak.RSATokenVerifier;
import org.keycloak.adapters.HttpClientBuilder;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.common.VerificationException;
import org.keycloak.common.util.KeystoreUtil;
import org.keycloak.common.util.PemUtils;
import org.keycloak.constants.AdapterConstants;
import org.keycloak.jose.jwk.JSONWebKeySet;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.jose.jws.crypto.RSAProvider;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
import org.keycloak.protocol.oidc.utils.OIDCResponseType;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.IDToken;
import org.keycloak.representations.RefreshToken;
import org.keycloak.representations.idm.KeysMetadataRepresentation;
import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
import org.keycloak.util.BasicAuthHelper;
import org.keycloak.util.JsonSerialization;
import org.keycloak.util.TokenUtil;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import javax.ws.rs.core.UriBuilder;
import java.io.Closeable;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.security.KeyStore;
import java.security.PublicKey;
import java.util.*;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
* @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
*/
public class OAuthClient {
public static final String SERVER_ROOT = AuthServerTestEnricher.getAuthServerContextRoot();
public static String AUTH_SERVER_ROOT = SERVER_ROOT + "/auth";
public static final String APP_ROOT = AUTH_SERVER_ROOT + "/realms/master/app";
private static final boolean sslRequired = Boolean.parseBoolean(System.getProperty("auth.server.ssl.required"));
private Keycloak adminClient;
private WebDriver driver;
private String baseUrl = AUTH_SERVER_ROOT;
private String realm;
private String clientId;
private String redirectUri;
private StateParamProvider state;
private String scope;
private String uiLocales;
private String clientSessionState;
private String clientSessionHost;
private String maxAge;
private String responseType = OAuth2Constants.CODE;
private String responseMode;
private String nonce;
private String request;
private String requestUri;
private Map<String, PublicKey> publicKeys = new HashMap<>();
// https://tools.ietf.org/html/rfc7636#section-4
private String codeVerifier;
private String codeChallenge;
private String codeChallengeMethod;
public class LogoutUrlBuilder {
private final UriBuilder b = OIDCLoginProtocolService.logoutUrl(UriBuilder.fromUri(baseUrl));
public LogoutUrlBuilder idTokenHint(String idTokenHint) {
if (idTokenHint != null) {
b.queryParam("id_token_hint", idTokenHint);
}
return this;
}
public LogoutUrlBuilder postLogoutRedirectUri(String redirectUri) {
if (redirectUri != null) {
b.queryParam("post_logout_redirect_uri", redirectUri);
}
return this;
}
public LogoutUrlBuilder redirectUri(String redirectUri) {
if (redirectUri != null) {
b.queryParam(OAuth2Constants.REDIRECT_URI, redirectUri);
}
return this;
}
public LogoutUrlBuilder sessionState(String sessionState) {
if (sessionState != null) {
b.queryParam("session_state", sessionState);
}
return this;
}
public String build() {
return b.build(realm).toString();
}
}
public void init(Keycloak adminClient, WebDriver driver) {
this.adminClient = adminClient;
this.driver = driver;
baseUrl = AUTH_SERVER_ROOT;
realm = "test";
clientId = "test-app";
redirectUri = APP_ROOT + "/auth";
state = () -> {
return KeycloakModelUtils.generateId();
};
scope = null;
uiLocales = null;
clientSessionState = null;
clientSessionHost = null;
maxAge = null;
nonce = null;
request = null;
requestUri = null;
// https://tools.ietf.org/html/rfc7636#section-4
codeVerifier = null;
codeChallenge = null;
codeChallengeMethod = null;
}
public AuthorizationEndpointResponse doLogin(String username, String password) {
openLoginForm();
fillLoginForm(username, password);
return new AuthorizationEndpointResponse(this);
}
public void fillLoginForm(String username, String password) {
String src = driver.getPageSource();
try {
driver.findElement(By.id("username")).sendKeys(username);
driver.findElement(By.id("password")).sendKeys(password);
driver.findElement(By.name("login")).click();
} catch (Throwable t) {
System.err.println(src);
throw t;
}
}
public void doLoginGrant(String username, String password) {
openLoginForm();
fillLoginForm(username, password);
}
private static CloseableHttpClient newCloseableHttpClient() {
if (sslRequired) {
KeyStore keystore = null;
// load the keystore containing the client certificate - keystore type is probably jks or pkcs12
String keyStorePath = System.getProperty("client.certificate.keystore");
String keyStorePassword = System.getProperty("client.certificate.keystore.passphrase");
try {
keystore = KeystoreUtil.loadKeyStore(keyStorePath, keyStorePassword);
} catch (Exception e) {
e.printStackTrace();
}
// load the trustore
KeyStore truststore = null;
String trustStorePath = System.getProperty("client.truststore");
String trustStorePassword = System.getProperty("client.truststore.passphrase");
try {
truststore = KeystoreUtil.loadKeyStore(trustStorePath, trustStorePassword);
} catch(Exception e) {
e.printStackTrace();
}
return (DefaultHttpClient)new HttpClientBuilder()
.keyStore(keystore, keyStorePassword)
.trustStore(truststore)
.hostnameVerification(HttpClientBuilder.HostnameVerificationPolicy.ANY)
.build();
}
return new DefaultHttpClient();
}
public AccessTokenResponse doAccessTokenRequest(String code, String password) {
CloseableHttpClient client = newCloseableHttpClient();
try {
HttpPost post = new HttpPost(getAccessTokenUrl());
List<NameValuePair> parameters = new LinkedList<NameValuePair>();
parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.AUTHORIZATION_CODE));
if (code != null) {
parameters.add(new BasicNameValuePair(OAuth2Constants.CODE, code));
}
if (redirectUri != null) {
parameters.add(new BasicNameValuePair(OAuth2Constants.REDIRECT_URI, redirectUri));
}
if (clientId != null && password != null) {
String authorization = BasicAuthHelper.createHeader(clientId, password);
post.setHeader("Authorization", authorization);
} else if (clientId != null) {
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ID, clientId));
}
if (clientSessionState != null) {
parameters.add(new BasicNameValuePair(AdapterConstants.CLIENT_SESSION_STATE, clientSessionState));
}
if (clientSessionHost != null) {
parameters.add(new BasicNameValuePair(AdapterConstants.CLIENT_SESSION_HOST, clientSessionHost));
}
// https://tools.ietf.org/html/rfc7636#section-4.5
if (codeVerifier != null) {
parameters.add(new BasicNameValuePair(OAuth2Constants.CODE_VERIFIER, codeVerifier));
}
UrlEncodedFormEntity formEntity = null;
try {
formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
post.setEntity(formEntity);
try {
return new AccessTokenResponse(client.execute(post));
} catch (Exception e) {
throw new RuntimeException("Failed to retrieve access token", e);
}
} finally {
closeClient(client);
}
}
public String introspectAccessTokenWithClientCredential(String clientId, String clientSecret, String tokenToIntrospect) {
return introspectTokenWithClientCredential(clientId, clientSecret, "access_token", tokenToIntrospect);
}
public String introspectRefreshTokenWithClientCredential(String clientId, String clientSecret, String tokenToIntrospect) {
return introspectTokenWithClientCredential(clientId, clientSecret, "refresh_token", tokenToIntrospect);
}
public String introspectTokenWithClientCredential(String clientId, String clientSecret, String tokenType, String tokenToIntrospect) {
CloseableHttpClient client = new DefaultHttpClient();
try {
HttpPost post = new HttpPost(getTokenIntrospectionUrl());
String authorization = BasicAuthHelper.createHeader(clientId, clientSecret);
post.setHeader("Authorization", authorization);
List<NameValuePair> parameters = new LinkedList<>();
parameters.add(new BasicNameValuePair("token", tokenToIntrospect));
parameters.add(new BasicNameValuePair("token_type_hint", tokenType));
UrlEncodedFormEntity formEntity;
try {
formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
post.setEntity(formEntity);
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
CloseableHttpResponse response = client.execute(post);
response.getEntity().writeTo(out);
response.close();
return new String(out.toByteArray());
} catch (Exception e) {
throw new RuntimeException("Failed to retrieve access token", e);
}
} finally {
closeClient(client);
}
}
public AccessTokenResponse doGrantAccessTokenRequest(String clientSecret, String username, String password) throws Exception {
return doGrantAccessTokenRequest(realm, username, password, null, clientId, clientSecret);
}
public AccessTokenResponse doGrantAccessTokenRequest(String clientSecret, String username, String password, String otp) throws Exception {
return doGrantAccessTokenRequest(realm, username, password, otp, clientId, clientSecret);
}
public AccessTokenResponse doGrantAccessTokenRequest(String realm, String username, String password, String totp,
String clientId, String clientSecret) throws Exception {
CloseableHttpClient client = newCloseableHttpClient();
try {
HttpPost post = new HttpPost(getResourceOwnerPasswordCredentialGrantUrl(realm));
List<NameValuePair> parameters = new LinkedList<NameValuePair>();
parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD));
parameters.add(new BasicNameValuePair("username", username));
parameters.add(new BasicNameValuePair("password", password));
if (totp != null) {
parameters.add(new BasicNameValuePair("totp", totp));
}
if (clientSecret != null) {
String authorization = BasicAuthHelper.createHeader(clientId, clientSecret);
post.setHeader("Authorization", authorization);
} else {
parameters.add(new BasicNameValuePair("client_id", clientId));
}
if (clientSessionState != null) {
parameters.add(new BasicNameValuePair(AdapterConstants.CLIENT_SESSION_STATE, clientSessionState));
}
if (clientSessionHost != null) {
parameters.add(new BasicNameValuePair(AdapterConstants.CLIENT_SESSION_HOST, clientSessionHost));
}
if (scope != null) {
parameters.add(new BasicNameValuePair(OAuth2Constants.SCOPE, scope));
}
UrlEncodedFormEntity formEntity;
try {
formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
post.setEntity(formEntity);
return new AccessTokenResponse(client.execute(post));
} finally {
closeClient(client);
}
}
public JSONWebKeySet doCertsRequest(String realm) throws Exception {
CloseableHttpClient client = new DefaultHttpClient();
try {
HttpGet get = new HttpGet(getCertsUrl(realm));
CloseableHttpResponse response = client.execute(get);
return JsonSerialization.readValue(response.getEntity().getContent(), JSONWebKeySet.class);
} finally {
closeClient(client);
}
}
public AccessTokenResponse doClientCredentialsGrantAccessTokenRequest(String clientSecret) throws Exception {
CloseableHttpClient client = new DefaultHttpClient();
try {
HttpPost post = new HttpPost(getServiceAccountUrl());
String authorization = BasicAuthHelper.createHeader(clientId, clientSecret);
post.setHeader("Authorization", authorization);
List<NameValuePair> parameters = new LinkedList<NameValuePair>();
parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.CLIENT_CREDENTIALS));
if (scope != null) {
parameters.add(new BasicNameValuePair(OAuth2Constants.SCOPE, scope));
}
UrlEncodedFormEntity formEntity;
try {
formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
post.setEntity(formEntity);
return new AccessTokenResponse(client.execute(post));
} finally {
closeClient(client);
}
}
public CloseableHttpResponse doLogout(String refreshToken, String clientSecret) throws IOException {
CloseableHttpClient client = new DefaultHttpClient();
try {
HttpPost post = new HttpPost(getLogoutUrl().build());
List<NameValuePair> parameters = new LinkedList<NameValuePair>();
if (refreshToken != null) {
parameters.add(new BasicNameValuePair(OAuth2Constants.REFRESH_TOKEN, refreshToken));
}
if (clientId != null && clientSecret != null) {
String authorization = BasicAuthHelper.createHeader(clientId, clientSecret);
post.setHeader("Authorization", authorization);
} else if (clientId != null) {
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ID, clientId));
}
UrlEncodedFormEntity formEntity;
try {
formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
post.setEntity(formEntity);
return client.execute(post);
} finally {
closeClient(client);
}
}
public AccessTokenResponse doRefreshTokenRequest(String refreshToken, String password) {
CloseableHttpClient client = new DefaultHttpClient();
try {
HttpPost post = new HttpPost(getRefreshTokenUrl());
List<NameValuePair> parameters = new LinkedList<NameValuePair>();
parameters.add(new BasicNameValuePair(OAuth2Constants.GRANT_TYPE, OAuth2Constants.REFRESH_TOKEN));
if (refreshToken != null) {
parameters.add(new BasicNameValuePair(OAuth2Constants.REFRESH_TOKEN, refreshToken));
}
if (clientId != null && password != null) {
String authorization = BasicAuthHelper.createHeader(clientId, password);
post.setHeader("Authorization", authorization);
} else if (clientId != null) {
parameters.add(new BasicNameValuePair(OAuth2Constants.CLIENT_ID, clientId));
}
if (clientSessionState != null) {
parameters.add(new BasicNameValuePair(AdapterConstants.CLIENT_SESSION_STATE, clientSessionState));
}
if (clientSessionHost != null) {
parameters.add(new BasicNameValuePair(AdapterConstants.CLIENT_SESSION_HOST, clientSessionHost));
}
UrlEncodedFormEntity formEntity;
try {
formEntity = new UrlEncodedFormEntity(parameters, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
post.setEntity(formEntity);
try {
return new AccessTokenResponse(client.execute(post));
} catch (Exception e) {
throw new RuntimeException("Failed to retrieve access token", e);
}
} finally {
closeClient(client);
}
}
public void closeClient(CloseableHttpClient client) {
try {
client.close();
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
public AccessToken verifyToken(String token) {
try {
return RSATokenVerifier.verifyToken(token, getRealmPublicKey(realm), baseUrl + "/realms/" + realm);
} catch (VerificationException e) {
throw new RuntimeException("Failed to verify token", e);
}
}
public IDToken verifyIDToken(String token) {
try {
IDToken idToken = RSATokenVerifier.verifyToken(token, getRealmPublicKey(realm), baseUrl + "/realms/" + realm, true, false);
Assert.assertEquals(TokenUtil.TOKEN_TYPE_ID, idToken.getType());
return idToken;
} catch (VerificationException e) {
throw new RuntimeException("Failed to verify token", e);
}
}
public RefreshToken verifyRefreshToken(String refreshToken) {
try {
JWSInput jws = new JWSInput(refreshToken);
if (!RSAProvider.verify(jws, getRealmPublicKey(realm))) {
throw new RuntimeException("Invalid refresh token");
}
return jws.readJsonContent(RefreshToken.class);
} catch (Exception e) {
throw new RuntimeException("Invalid refresh token", e);
}
}
public String getClientId() {
return clientId;
}
public String getCurrentRequest() {
int index = driver.getCurrentUrl().indexOf('?');
if (index == -1) {
index = driver.getCurrentUrl().indexOf('#');
}
return driver.getCurrentUrl().substring(0, index);
}
public URI getCurrentUri() {
try {
return new URI(driver.getCurrentUrl());
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
public Map<String, String> getCurrentQuery() {
Map<String, String> m = new HashMap<String, String>();
List<NameValuePair> pairs = URLEncodedUtils.parse(getCurrentUri(), "UTF-8");
for (NameValuePair p : pairs) {
m.put(p.getName(), p.getValue());
}
return m;
}
public Map<String, String> getCurrentFragment() {
Map<String, String> m = new HashMap<String, String>();
String fragment = getCurrentUri().getRawFragment();
List<NameValuePair> pairs = (fragment == null || fragment.isEmpty()) ? Collections.emptyList() : URLEncodedUtils.parse(fragment, Charset.forName("UTF-8"));
for (NameValuePair p : pairs) {
m.put(p.getName(), p.getValue());
}
return m;
}
public void openLoginForm() {
driver.navigate().to(getLoginFormUrl());
}
public void openLogout() {
UriBuilder b = OIDCLoginProtocolService.logoutUrl(UriBuilder.fromUri(baseUrl));
if (redirectUri != null) {
b.queryParam(OAuth2Constants.REDIRECT_URI, redirectUri);
}
driver.navigate().to(b.build(realm).toString());
}
public String getRedirectUri() {
return redirectUri;
}
public String getLoginFormUrl() {
UriBuilder b = OIDCLoginProtocolService.authUrl(UriBuilder.fromUri(AUTH_SERVER_ROOT));
if (responseType != null) {
b.queryParam(OAuth2Constants.RESPONSE_TYPE, responseType);
}
if (responseMode != null) {
b.queryParam(OIDCLoginProtocol.RESPONSE_MODE_PARAM, responseMode);
}
if (clientId != null) {
b.queryParam(OAuth2Constants.CLIENT_ID, clientId);
}
if (redirectUri != null) {
b.queryParam(OAuth2Constants.REDIRECT_URI, redirectUri);
}
String state = this.state.getState();
if (state != null) {
b.queryParam(OAuth2Constants.STATE, state);
}
if (uiLocales != null){
b.queryParam(OAuth2Constants.UI_LOCALES_PARAM, uiLocales);
}
if (nonce != null){
b.queryParam(OIDCLoginProtocol.NONCE_PARAM, nonce);
}
String scopeParam = TokenUtil.attachOIDCScope(scope);
b.queryParam(OAuth2Constants.SCOPE, scopeParam);
if (maxAge != null) {
b.queryParam(OIDCLoginProtocol.MAX_AGE_PARAM, maxAge);
}
if (request != null) {
b.queryParam(OIDCLoginProtocol.REQUEST_PARAM, request);
}
if (requestUri != null) {
b.queryParam(OIDCLoginProtocol.REQUEST_URI_PARAM, requestUri);
}
// https://tools.ietf.org/html/rfc7636#section-4.3
if (codeChallenge != null) {
b.queryParam(OAuth2Constants.CODE_CHALLENGE, codeChallenge);
}
if (codeChallengeMethod != null) {
b.queryParam(OAuth2Constants.CODE_CHALLENGE_METHOD, codeChallengeMethod);
}
return b.build(realm).toString();
}
public String getAccessTokenUrl() {
UriBuilder b = OIDCLoginProtocolService.tokenUrl(UriBuilder.fromUri(baseUrl));
return b.build(realm).toString();
}
public String getTokenIntrospectionUrl() {
UriBuilder b = OIDCLoginProtocolService.tokenIntrospectionUrl(UriBuilder.fromUri(baseUrl));
return b.build(realm).toString();
}
public LogoutUrlBuilder getLogoutUrl() {
return new LogoutUrlBuilder();
}
public String getResourceOwnerPasswordCredentialGrantUrl() {
UriBuilder b = OIDCLoginProtocolService.tokenUrl(UriBuilder.fromUri(baseUrl));
return b.build(realm).toString();
}
public String getResourceOwnerPasswordCredentialGrantUrl(String realm) {
UriBuilder b = OIDCLoginProtocolService.tokenUrl(UriBuilder.fromUri(baseUrl));
return b.build(realm).toString();
}
public String getCertsUrl(String realm) {
UriBuilder b = OIDCLoginProtocolService.certsUrl(UriBuilder.fromUri(baseUrl));
return b.build(realm).toString();
}
public String getServiceAccountUrl() {
return getResourceOwnerPasswordCredentialGrantUrl();
}
public String getRefreshTokenUrl() {
UriBuilder b = OIDCLoginProtocolService.tokenUrl(UriBuilder.fromUri(baseUrl));
return b.build(realm).toString();
}
public OAuthClient realm(String realm) {
this.realm = realm;
return this;
}
public OAuthClient clientId(String clientId) {
this.clientId = clientId;
return this;
}
public OAuthClient redirectUri(String redirectUri) {
this.redirectUri = redirectUri;
return this;
}
public OAuthClient stateParamHardcoded(String value) {
this.state = () -> {
return value;
};
return this;
}
public OAuthClient stateParamRandom() {
this.state = () -> {
return KeycloakModelUtils.generateId();
};
return this;
}
public OAuthClient scope(String scope) {
this.scope = scope;
return this;
}
public OAuthClient uiLocales(String uiLocales){
this.uiLocales = uiLocales;
return this;
}
public OAuthClient clientSessionState(String client_session_state) {
this.clientSessionState = client_session_state;
return this;
}
public OAuthClient clientSessionHost(String client_session_host) {
this.clientSessionHost = client_session_host;
return this;
}
public OAuthClient maxAge(String maxAge) {
this.maxAge = maxAge;
return this;
}
public OAuthClient responseType(String responseType) {
this.responseType = responseType;
return this;
}
public OAuthClient responseMode(String responseMode) {
this.responseMode = responseMode;
return this;
}
public OAuthClient nonce(String nonce) {
this.nonce = nonce;
return this;
}
public OAuthClient request(String request) {
this.request = request;
return this;
}
public OAuthClient requestUri(String requestUri) {
this.requestUri = requestUri;
return this;
}
public String getRealm() {
return realm;
}
// https://tools.ietf.org/html/rfc7636#section-4
public OAuthClient codeVerifier(String codeVerifier) {
this.codeVerifier = codeVerifier;
return this;
}
public OAuthClient codeChallenge(String codeChallenge) {
this.codeChallenge = codeChallenge;
return this;
}
public OAuthClient codeChallengeMethod(String codeChallengeMethod) {
this.codeChallengeMethod = codeChallengeMethod;
return this;
}
public static class AuthorizationEndpointResponse {
private boolean isRedirected;
private String code;
private String state;
private String error;
private String errorDescription;
// Just during OIDC implicit or hybrid flow
private String accessToken;
private String idToken;
public AuthorizationEndpointResponse(OAuthClient client) {
boolean fragment;
try {
fragment = client.responseType != null && OIDCResponseType.parse(client.responseType).isImplicitOrHybridFlow();
} catch (IllegalArgumentException iae) {
fragment = false;
}
init (client, fragment);
}
public AuthorizationEndpointResponse(OAuthClient client, boolean fragment) {
init(client, fragment);
}
private void init(OAuthClient client, boolean fragment) {
isRedirected = client.getCurrentRequest().equals(client.getRedirectUri());
Map<String, String> params = fragment ? client.getCurrentFragment() : client.getCurrentQuery();
code = params.get(OAuth2Constants.CODE);
state = params.get(OAuth2Constants.STATE);
error = params.get(OAuth2Constants.ERROR);
errorDescription = params.get(OAuth2Constants.ERROR_DESCRIPTION);
accessToken = params.get(OAuth2Constants.ACCESS_TOKEN);
idToken = params.get(OAuth2Constants.ID_TOKEN);
}
public boolean isRedirected() {
return isRedirected;
}
public String getCode() {
return code;
}
public String getState() {
return state;
}
public String getError() {
return error;
}
public String getErrorDescription() {
return errorDescription;
}
public String getAccessToken() {
return accessToken;
}
public String getIdToken() {
return idToken;
}
}
public static class AccessTokenResponse {
private int statusCode;
private String idToken;
private String accessToken;
private String tokenType;
private int expiresIn;
private int refreshExpiresIn;
private String refreshToken;
private String error;
private String errorDescription;
public AccessTokenResponse(CloseableHttpResponse response) throws Exception {
try {
statusCode = response.getStatusLine().getStatusCode();
if (!"application/json".equals(response.getHeaders("Content-Type")[0].getValue())) {
Assert.fail("Invalid content type");
}
String s = IOUtils.toString(response.getEntity().getContent());
Map responseJson = JsonSerialization.readValue(s, Map.class);
if (statusCode == 200) {
idToken = (String) responseJson.get("id_token");
accessToken = (String) responseJson.get("access_token");
tokenType = (String) responseJson.get("token_type");
expiresIn = (Integer) responseJson.get("expires_in");
refreshExpiresIn = (Integer) responseJson.get("refresh_expires_in");
if (responseJson.containsKey(OAuth2Constants.REFRESH_TOKEN)) {
refreshToken = (String) responseJson.get(OAuth2Constants.REFRESH_TOKEN);
}
} else {
error = (String) responseJson.get(OAuth2Constants.ERROR);
errorDescription = responseJson.containsKey(OAuth2Constants.ERROR_DESCRIPTION) ? (String) responseJson.get(OAuth2Constants.ERROR_DESCRIPTION) : null;
}
} finally {
response.close();
}
}
public String getIdToken() {
return idToken;
}
public String getAccessToken() {
return accessToken;
}
public String getError() {
return error;
}
public String getErrorDescription() {
return errorDescription;
}
public int getExpiresIn() {
return expiresIn;
}
public int getRefreshExpiresIn() {
return refreshExpiresIn;
}
public int getStatusCode() {
return statusCode;
}
public String getRefreshToken() {
return refreshToken;
}
public String getTokenType() {
return tokenType;
}
}
public PublicKey getRealmPublicKey(String realm) {
if (!publicKeys.containsKey(realm)) {
KeysMetadataRepresentation keyMetadata = adminClient.realms().realm(realm).keys().getKeyMetadata();
String activeKid = keyMetadata.getActive().get("RSA");
PublicKey publicKey = null;
for (KeysMetadataRepresentation.KeyMetadataRepresentation rep : keyMetadata.getKeys()) {
if (rep.getKid().equals(activeKid)) {
publicKey = PemUtils.decodePublicKey(rep.getPublicKey());
}
}
publicKeys.put(realm, publicKey);
}
return publicKeys.get(realm);
}
private interface StateParamProvider {
String getState();
}
}