/*
* oxAuth is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text.
*
* Copyright (c) 2014, Gluu
*/
package org.xdi.oxauth.client;
import org.apache.commons.lang.StringUtils;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.xdi.oxauth.model.common.AuthorizationMethod;
import org.xdi.oxauth.model.crypto.OxAuthCryptoProvider;
import org.xdi.oxauth.model.jwe.Jwe;
import org.xdi.oxauth.model.jwt.Jwt;
import org.xdi.oxauth.model.userinfo.UserInfoErrorResponseType;
import org.xdi.oxauth.model.util.JwtUtil;
import org.xdi.oxauth.model.util.Util;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.MediaType;
import java.security.PrivateKey;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Encapsulates functionality to make user info request calls to an authorization server via REST Services.
*
* @author Javier Rojas Blum
* @version December 26, 2016
*/
public class UserInfoClient extends BaseClient<UserInfoRequest, UserInfoResponse> {
private String sharedKey;
private PrivateKey privateKey;
private String jwksUri;
/**
* Constructs an User Info client by providing a REST url where the service is located.
*
* @param url The REST Service location.
*/
public UserInfoClient(String url) {
super(url);
}
@Override
public String getHttpMethod() {
if (request.getAuthorizationMethod() == null
|| request.getAuthorizationMethod() == AuthorizationMethod.AUTHORIZATION_REQUEST_HEADER_FIELD
|| request.getAuthorizationMethod() == AuthorizationMethod.URL_QUERY_PARAMETER) {
return HttpMethod.GET;
} else /*if (request.getAuthorizationMethod() == AuthorizationMethod.FORM_ENCODED_BODY_PARAMETER)*/ {
return HttpMethod.POST;
}
}
/**
* Executes the call to the REST Service and processes the response.
*
* @param accessToken The access token obtained from the oxAuth authorization request.
* @return The service response.
*/
public UserInfoResponse execUserInfo(String accessToken) {
setRequest(new UserInfoRequest(accessToken));
return exec();
}
/**
* Executes the call to the REST Service and processes the response.
*
* @return The service response.
*/
public UserInfoResponse exec() {
// Prepare request parameters
initClientRequest();
clientRequest.header("Content-Type", MediaType.APPLICATION_FORM_URLENCODED);
clientRequest.setHttpMethod(getHttpMethod());
if (getRequest().getAuthorizationMethod() == null
|| getRequest().getAuthorizationMethod() == AuthorizationMethod.AUTHORIZATION_REQUEST_HEADER_FIELD) {
if (StringUtils.isNotBlank(getRequest().getAccessToken())) {
clientRequest.header("Authorization", "Bearer " + getRequest().getAccessToken());
}
} else if (getRequest().getAuthorizationMethod() == AuthorizationMethod.FORM_ENCODED_BODY_PARAMETER) {
if (StringUtils.isNotBlank(getRequest().getAccessToken())) {
clientRequest.formParameter("access_token", getRequest().getAccessToken());
}
} else if (getRequest().getAuthorizationMethod() == AuthorizationMethod.URL_QUERY_PARAMETER) {
if (StringUtils.isNotBlank(getRequest().getAccessToken())) {
clientRequest.queryParameter("access_token", getRequest().getAccessToken());
}
}
// Call REST Service and handle response
try {
if (getRequest().getAuthorizationMethod() == null
|| getRequest().getAuthorizationMethod() == AuthorizationMethod.AUTHORIZATION_REQUEST_HEADER_FIELD
|| getRequest().getAuthorizationMethod() == AuthorizationMethod.URL_QUERY_PARAMETER) {
clientResponse = clientRequest.get(String.class);
} else if (getRequest().getAuthorizationMethod() == AuthorizationMethod.FORM_ENCODED_BODY_PARAMETER) {
clientResponse = clientRequest.post(String.class);
}
int status = clientResponse.getStatus();
setResponse(new UserInfoResponse(status));
String entity = clientResponse.getEntity(String.class);
getResponse().setEntity(entity);
getResponse().setHeaders(clientResponse.getMetadata());
if (StringUtils.isNotBlank(entity)) {
List<Object> contentType = clientResponse.getHeaders().get("Content-Type");
if (contentType != null && contentType.contains("application/jwt")) {
String[] jwtParts = entity.split("\\.");
if (jwtParts.length == 5) {
byte[] sharedSymmetricKey = sharedKey != null ? sharedKey.getBytes(Util.UTF8_STRING_ENCODING) : null;
Jwe jwe = Jwe.parse(entity, privateKey, sharedSymmetricKey);
getResponse().setClaims(jwe.getClaims().toMap());
} else {
Jwt jwt = Jwt.parse(entity);
OxAuthCryptoProvider cryptoProvider = new OxAuthCryptoProvider();
boolean signatureVerified = cryptoProvider.verifySignature(
jwt.getSigningInput(),
jwt.getEncodedSignature(),
jwt.getHeader().getKeyId(),
JwtUtil.getJSONWebKeys(jwksUri),
sharedKey,
jwt.getHeader().getAlgorithm());
if (signatureVerified) {
getResponse().setClaims(jwt.getClaims().toMap());
}
}
} else {
try {
JSONObject jsonObj = new JSONObject(entity);
if (jsonObj.has("error")) {
getResponse().setErrorType(UserInfoErrorResponseType.fromString(jsonObj.getString("error")));
jsonObj.remove("error");
}
if (jsonObj.has("error_description")) {
getResponse().setErrorDescription(jsonObj.getString("error_description"));
jsonObj.remove("error_description");
}
if (jsonObj.has("error_uri")) {
getResponse().setErrorUri(jsonObj.getString("error_uri"));
jsonObj.remove("error_uri");
}
for (Iterator<String> iterator = jsonObj.keys(); iterator.hasNext(); ) {
String key = iterator.next();
List<String> values = new ArrayList<String>();
JSONArray jsonArray = jsonObj.optJSONArray(key);
if (jsonArray != null) {
for (int i = 0; i < jsonArray.length(); i++) {
String value = jsonArray.optString(i);
if (value != null) {
values.add(value);
}
}
} else {
String value = jsonObj.optString(key);
if (value != null) {
values.add(value);
}
}
getResponse().getClaims().put(key, values);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
closeConnection();
}
return getResponse();
}
public void setSharedKey(String sharedKey) {
this.sharedKey = sharedKey;
}
public void setPrivateKey(PrivateKey privateKey) {
this.privateKey = privateKey;
}
public String getJwksUri() {
return jwksUri;
}
public void setJwksUri(String jwksUri) {
this.jwksUri = jwksUri;
}
}