From 871970002aca8d89915d44c32a3658de725e3025 Mon Sep 17 00:00:00 2001 From: amalhub Date: Fri, 9 Dec 2016 11:47:58 +0530 Subject: [PATCH] IOTS-292: Adding android cert verification for gateway handler --- .../AuthenticationHandler.java | 164 +++++++++++++----- .../utils/AuthConstants.java | 5 +- 2 files changed, 118 insertions(+), 51 deletions(-) diff --git a/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/AuthenticationHandler.java b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/AuthenticationHandler.java index f5c5c800563..770ffd1128e 100644 --- a/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/AuthenticationHandler.java +++ b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/AuthenticationHandler.java @@ -30,6 +30,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.ws.security.WSConstants; import org.apache.ws.security.WSSecurityException; import org.apache.ws.security.util.Base64; +import org.json.JSONException; import org.json.JSONObject; import org.wso2.carbon.apimgt.handlers.invoker.RESTInvoker; import org.wso2.carbon.apimgt.handlers.invoker.RESTResponse; @@ -37,7 +38,9 @@ import org.wso2.carbon.apimgt.handlers.utils.AuthConstants; import org.wso2.carbon.apimgt.handlers.utils.CoreUtils; import javax.xml.namespace.QName; +import java.io.IOException; import java.net.URI; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -68,52 +71,17 @@ public class AuthenticationHandler implements Handler { * @throws AxisFault */ public InvocationResponse invoke(MessageContext messageContext) throws AxisFault { - boolean validateRequest = messageContext.getTo() != null; - - if (validateRequest && isSecuredAPI(messageContext)) { + if (isSecuredAPI(messageContext)) { String ctxPath = messageContext.getTo().getAddress().trim(); CoreUtils.debugLog(log, "Authentication handler invoked by: ", ctxPath); Map headers = (Map) messageContext.getProperty(MessageContext.TRANSPORT_HEADERS); + try { + if (headers.containsKey(AuthConstants.MDM_SIGNATURE)) { - if (headers.containsKey(AuthConstants.MDM_SIGNATURE)) { - String mdmSignature = headers.get(AuthConstants.MDM_SIGNATURE).toString(); - - try { + String mdmSignature = headers.get(AuthConstants.MDM_SIGNATURE).toString(); CoreUtils.debugLog(log, "Verify Cert:\n", mdmSignature); - URI dcrUrl = new URI(AuthConstants.HTTPS + "://" + CoreUtils.getHost() + ":" + CoreUtils - .getHttpsPort() + "/dynamic-client-web/register"); - String dcrContent = "{\n" + - "\"owner\":\"" + CoreUtils.getUsername() + "\",\n" + - "\"clientName\":\"emm\",\n" + - "\"grantType\":\"refresh_token password client_credentials\",\n" + - "\"tokenScope\":\"default\"\n" + - "}"; - Map drcHeaders = new HashMap(); - drcHeaders.put("Content-Type", "application/json"); - - RESTResponse response = restInvoker.invokePOST(dcrUrl, drcHeaders, null, - null, dcrContent); - CoreUtils.debugLog(log, "DCR response:", response.getContent()); - JSONObject jsonResponse = new JSONObject(response.getContent()); - String clientId = jsonResponse.getString("client_id"); - String clientSecret = jsonResponse.getString("client_secret"); - - URI tokenUrl = new URI(AuthConstants.HTTPS + "://" + CoreUtils.getHost() + ":" + CoreUtils - .getHttpsPort() + "/oauth2/token"); - String tokenContent = "grant_type=password&username=" + CoreUtils.getUsername() + "&password=" + - CoreUtils.getPassword() + "&scope=activity-view"; - String tokenBasicAuth = "Basic " + Base64.encode((clientId + ":" + clientSecret).getBytes()); - Map tokenHeaders = new HashMap(); - tokenHeaders.put("Authorization", tokenBasicAuth); - tokenHeaders.put("Content-Type", "application/x-www-form-urlencoded"); - - response = restInvoker.invokePOST(tokenUrl, tokenHeaders, null, - null, tokenContent); - CoreUtils.debugLog(log, "Token response:", response.getContent()); - jsonResponse = new JSONObject(response.getContent()); - String accessToken = jsonResponse.getString("access_token"); - + String accessToken = getAccessToken(); URI certVerifyUrl = new URI(AuthConstants.HTTPS + "://" + CoreUtils.getHost() + ":" + CoreUtils .getHttpsPort() + "/api/certificate-mgt/v1.0/admin/certificates/verify/ios"); Map certVerifyHeaders = new HashMap(); @@ -125,7 +93,7 @@ public class AuthenticationHandler implements Handler { "\"serial\":\"\"\n" + "}"; - response = restInvoker.invokePOST(certVerifyUrl, certVerifyHeaders, null, + RESTResponse response = restInvoker.invokePOST(certVerifyUrl, certVerifyHeaders, null, null, certVerifyContent); CoreUtils.debugLog(log, "Verify response:", response.getContent()); @@ -136,14 +104,65 @@ public class AuthenticationHandler implements Handler { setFaultCodeAndThrowAxisFault(messageContext, new Exception("Unauthorized!")); return InvocationResponse.SUSPEND; - } catch (Exception e) { - log.error("Error while processing certificate.", e); - setFaultCodeAndThrowAxisFault(messageContext, e); + } else if (headers.containsKey(AuthConstants.PROXY_MUTUAL_AUTH_HEADER)) { + String subjectDN = headers.get(AuthConstants.PROXY_MUTUAL_AUTH_HEADER).toString(); + CoreUtils.debugLog(log, "Verify subject DN: ", subjectDN); + String accessToken = getAccessToken(); + URI certVerifyUrl = new URI(AuthConstants.HTTPS + "://" + CoreUtils.getHost() + ":" + CoreUtils + .getHttpsPort() + "/api/certificate-mgt/v1.0/admin/certificates/verify/android"); + Map certVerifyHeaders = new HashMap(); + certVerifyHeaders.put("Authorization", "Bearer " + accessToken); + certVerifyHeaders.put("Content-Type", "application/json"); + String certVerifyContent = "{\n" + + "\"pem\":\"" + subjectDN + "\",\n" + + "\"tenantId\": \"-1234\",\n" + + "\"serial\":\"" + AuthConstants.PROXY_MUTUAL_AUTH_HEADER + "\"\n" + + "}"; + + RESTResponse response = restInvoker.invokePOST(certVerifyUrl, certVerifyHeaders, null, + null, certVerifyContent); + CoreUtils.debugLog(log, "Verify response:", response.getContent()); + if (!response.getContent().contains("invalid")) { + return InvocationResponse.CONTINUE; + } + log.warn("Unauthorized request for api: " + ctxPath); + setFaultCodeAndThrowAxisFault(messageContext, new Exception("Unauthorized!")); + return InvocationResponse.SUSPEND; + + } else if (headers.containsKey(AuthConstants.ENCODED_PEM)) { + String encodedPem = headers.get(AuthConstants.ENCODED_PEM).toString(); + CoreUtils.debugLog(log, "Verify Cert:\n", encodedPem); + + String accessToken = getAccessToken(); + URI certVerifyUrl = new URI(AuthConstants.HTTPS + "://" + CoreUtils.getHost() + ":" + CoreUtils + .getHttpsPort() + "/api/certificate-mgt/v1.0/admin/certificates/verify/ios"); + Map certVerifyHeaders = new HashMap(); + certVerifyHeaders.put("Authorization", "Bearer " + accessToken); + certVerifyHeaders.put("Content-Type", "application/json"); + String certVerifyContent = "{\n" + + "\"pem\":\"" + encodedPem + "\",\n" + + "\"tenantId\": \"-1234\",\n" + + "\"serial\":\"\"\n" + + "}"; + + RESTResponse response = restInvoker.invokePOST(certVerifyUrl, certVerifyHeaders, null, + null, certVerifyContent); + CoreUtils.debugLog(log, "Verify response:", response.getContent()); + + if (!response.getContent().contains("invalid")) { + return InvocationResponse.CONTINUE; + } + log.warn("Unauthorized request for api: " + ctxPath); + setFaultCodeAndThrowAxisFault(messageContext, new Exception("Unauthorized!")); + return InvocationResponse.SUSPEND; + } else { + log.warn("Unauthorized request for api: " + ctxPath); + setFaultCodeAndThrowAxisFault(messageContext, new Exception("SSL required")); return InvocationResponse.SUSPEND; } - } else { - log.warn("Unauthorized request for api: " + ctxPath); - setFaultCodeAndThrowAxisFault(messageContext, new Exception("SSL required")); + } catch (Exception e) { + log.error("Error while processing certificate.", e); + setFaultCodeAndThrowAxisFault(messageContext, e); return InvocationResponse.SUSPEND; } } else { @@ -159,7 +178,7 @@ public class AuthenticationHandler implements Handler { * @return boolean */ private boolean isSecuredAPI(MessageContext messageContext) { - if (messageContext.getTransportIn() != null && + if (messageContext.getTo() != null && messageContext.getTransportIn() != null && messageContext.getTransportIn().getName().toLowerCase().equals(AuthConstants.HTTPS)) { for (String path : apiList) { if (messageContext.getTo().getAddress().trim().contains(path)) { @@ -170,6 +189,55 @@ public class AuthenticationHandler implements Handler { return false; } + /** + * Get access token to call admin certificate management service for cert validation. + * + * @return accessToken String + * @throws URISyntaxException + * @throws IOException + */ + private String getAccessToken() throws URISyntaxException, IOException, JSONException { + URI dcrUrl = new URI(AuthConstants.HTTPS + "://" + CoreUtils.getHost() + ":" + CoreUtils + .getHttpsPort() + "/dynamic-client-web/register"); + String dcrContent = "{\n" + + "\"owner\":\"" + CoreUtils.getUsername() + "\",\n" + + "\"clientName\":\"emm\",\n" + + "\"grantType\":\"refresh_token password client_credentials\",\n" + + "\"tokenScope\":\"default\"\n" + + "}"; + Map drcHeaders = new HashMap(); + drcHeaders.put("Content-Type", "application/json"); + + RESTResponse response = restInvoker.invokePOST(dcrUrl, drcHeaders, null, + null, dcrContent); + CoreUtils.debugLog(log, "DCR response:", response.getContent()); + JSONObject jsonResponse = new JSONObject(response.getContent()); + String clientId = jsonResponse.getString("client_id"); + String clientSecret = jsonResponse.getString("client_secret"); + + URI tokenUrl = new URI(AuthConstants.HTTPS + "://" + CoreUtils.getHost() + ":" + CoreUtils + .getHttpsPort() + "/oauth2/token"); + String tokenContent = "grant_type=password&username=" + CoreUtils.getUsername() + "&password=" + + CoreUtils.getPassword() + "&scope=activity-view"; + String tokenBasicAuth = "Basic " + Base64.encode((clientId + ":" + clientSecret).getBytes()); + Map tokenHeaders = new HashMap(); + tokenHeaders.put("Authorization", tokenBasicAuth); + tokenHeaders.put("Content-Type", "application/x-www-form-urlencoded"); + + response = restInvoker.invokePOST(tokenUrl, tokenHeaders, null, + null, tokenContent); + CoreUtils.debugLog(log, "Token response:", response.getContent()); + jsonResponse = new JSONObject(response.getContent()); + String accessToken = jsonResponse.getString("access_token"); + return accessToken; + } + + /** + * Thow error message to client + * @param msgContext + * @param e Exception + * @throws AxisFault + */ private void setFaultCodeAndThrowAxisFault(MessageContext msgContext, Exception e) throws AxisFault { msgContext.setProperty(AuthConstants.SEC_FAULT, Boolean.TRUE); diff --git a/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/utils/AuthConstants.java b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/utils/AuthConstants.java index b7c9a00dfae..12bcda249a5 100644 --- a/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/utils/AuthConstants.java +++ b/components/apimgt-extensions/org.wso2.carbon.apimgt.handlers/src/main/java/org.wso2.carbon.apimgt.handlers/utils/AuthConstants.java @@ -21,7 +21,6 @@ public class AuthConstants { public static final String SEC_FAULT = "SECURITY_VALIDATION_FAILURE"; public static final String HTTPS = "https"; public static final String WSSE = "wsse"; - public static final String SSL_CERT_X509 = "ssl.client.auth.cert.X509"; public static final String AUTH_CONFIGURATION_FILE_NAME = "api-filter-config.xml"; public static final String API_FILTER_CONFIG_ELEMENT = "apiFilterConfig"; public static final String API_LIST_PROPERTY = "apiList"; @@ -30,6 +29,6 @@ public class AuthConstants { public static final String USERNAME = "username"; public static final String PASSWORD = "password"; public static final String MDM_SIGNATURE = "mdm-signature"; - public static final String IOS = "ios"; - public static final String ANDROID = "android"; + public static final String PROXY_MUTUAL_AUTH_HEADER = "proxy-mutual-auth-header"; + public static final String ENCODED_PEM = "encoded-pem"; }