IOTS-292: Adding android cert verification for gateway handler

4.x.x
amalhub 8 years ago
parent 610163d705
commit 871970002a

@ -30,6 +30,7 @@ import org.apache.commons.logging.LogFactory;
import org.apache.ws.security.WSConstants; import org.apache.ws.security.WSConstants;
import org.apache.ws.security.WSSecurityException; import org.apache.ws.security.WSSecurityException;
import org.apache.ws.security.util.Base64; import org.apache.ws.security.util.Base64;
import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.wso2.carbon.apimgt.handlers.invoker.RESTInvoker; import org.wso2.carbon.apimgt.handlers.invoker.RESTInvoker;
import org.wso2.carbon.apimgt.handlers.invoker.RESTResponse; 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 org.wso2.carbon.apimgt.handlers.utils.CoreUtils;
import javax.xml.namespace.QName; import javax.xml.namespace.QName;
import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -68,64 +71,81 @@ public class AuthenticationHandler implements Handler {
* @throws AxisFault * @throws AxisFault
*/ */
public InvocationResponse invoke(MessageContext messageContext) throws AxisFault { public InvocationResponse invoke(MessageContext messageContext) throws AxisFault {
boolean validateRequest = messageContext.getTo() != null; if (isSecuredAPI(messageContext)) {
if (validateRequest && isSecuredAPI(messageContext)) {
String ctxPath = messageContext.getTo().getAddress().trim(); String ctxPath = messageContext.getTo().getAddress().trim();
CoreUtils.debugLog(log, "Authentication handler invoked by: ", ctxPath); CoreUtils.debugLog(log, "Authentication handler invoked by: ", ctxPath);
Map<?, ?> headers = (Map<?, ?>) messageContext.getProperty(MessageContext.TRANSPORT_HEADERS); 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); CoreUtils.debugLog(log, "Verify Cert:\n", mdmSignature);
URI dcrUrl = new URI(AuthConstants.HTTPS + "://" + CoreUtils.getHost() + ":" + CoreUtils String accessToken = getAccessToken();
.getHttpsPort() + "/dynamic-client-web/register"); URI certVerifyUrl = new URI(AuthConstants.HTTPS + "://" + CoreUtils.getHost() + ":" + CoreUtils
String dcrContent = "{\n" + .getHttpsPort() + "/api/certificate-mgt/v1.0/admin/certificates/verify/ios");
"\"owner\":\"" + CoreUtils.getUsername() + "\",\n" + Map<String, String> certVerifyHeaders = new HashMap<String, String>();
"\"clientName\":\"emm\",\n" + certVerifyHeaders.put("Authorization", "Bearer " + accessToken);
"\"grantType\":\"refresh_token password client_credentials\",\n" + certVerifyHeaders.put("Content-Type", "application/json");
"\"tokenScope\":\"default\"\n" + String certVerifyContent = "{\n" +
"\"pem\":\"" + mdmSignature + "\",\n" +
"\"tenantId\": \"-1234\",\n" +
"\"serial\":\"\"\n" +
"}"; "}";
Map<String, String> drcHeaders = new HashMap<String, String>();
drcHeaders.put("Content-Type", "application/json");
RESTResponse response = restInvoker.invokePOST(dcrUrl, drcHeaders, null, RESTResponse response = restInvoker.invokePOST(certVerifyUrl, certVerifyHeaders, null,
null, dcrContent); null, certVerifyContent);
CoreUtils.debugLog(log, "DCR response:", response.getContent()); CoreUtils.debugLog(log, "Verify 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 if (!response.getContent().contains("invalid")) {
.getHttpsPort() + "/oauth2/token"); return InvocationResponse.CONTINUE;
String tokenContent = "grant_type=password&username=" + CoreUtils.getUsername() + "&password=" + }
CoreUtils.getPassword() + "&scope=activity-view"; log.warn("Unauthorized request for api: " + ctxPath);
String tokenBasicAuth = "Basic " + Base64.encode((clientId + ":" + clientSecret).getBytes()); setFaultCodeAndThrowAxisFault(messageContext, new Exception("Unauthorized!"));
Map<String, String> tokenHeaders = new HashMap<String, String>(); return InvocationResponse.SUSPEND;
tokenHeaders.put("Authorization", tokenBasicAuth);
tokenHeaders.put("Content-Type", "application/x-www-form-urlencoded");
response = restInvoker.invokePOST(tokenUrl, tokenHeaders, null, } else if (headers.containsKey(AuthConstants.PROXY_MUTUAL_AUTH_HEADER)) {
null, tokenContent); String subjectDN = headers.get(AuthConstants.PROXY_MUTUAL_AUTH_HEADER).toString();
CoreUtils.debugLog(log, "Token response:", response.getContent()); CoreUtils.debugLog(log, "Verify subject DN: ", subjectDN);
jsonResponse = new JSONObject(response.getContent()); String accessToken = getAccessToken();
String accessToken = jsonResponse.getString("access_token"); URI certVerifyUrl = new URI(AuthConstants.HTTPS + "://" + CoreUtils.getHost() + ":" + CoreUtils
.getHttpsPort() + "/api/certificate-mgt/v1.0/admin/certificates/verify/android");
Map<String, String> certVerifyHeaders = new HashMap<String, String>();
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 URI certVerifyUrl = new URI(AuthConstants.HTTPS + "://" + CoreUtils.getHost() + ":" + CoreUtils
.getHttpsPort() + "/api/certificate-mgt/v1.0/admin/certificates/verify/ios"); .getHttpsPort() + "/api/certificate-mgt/v1.0/admin/certificates/verify/ios");
Map<String, String> certVerifyHeaders = new HashMap<String, String>(); Map<String, String> certVerifyHeaders = new HashMap<String, String>();
certVerifyHeaders.put("Authorization", "Bearer " + accessToken); certVerifyHeaders.put("Authorization", "Bearer " + accessToken);
certVerifyHeaders.put("Content-Type", "application/json"); certVerifyHeaders.put("Content-Type", "application/json");
String certVerifyContent = "{\n" + String certVerifyContent = "{\n" +
"\"pem\":\"" + mdmSignature + "\",\n" + "\"pem\":\"" + encodedPem + "\",\n" +
"\"tenantId\": \"-1234\",\n" + "\"tenantId\": \"-1234\",\n" +
"\"serial\":\"\"\n" + "\"serial\":\"\"\n" +
"}"; "}";
response = restInvoker.invokePOST(certVerifyUrl, certVerifyHeaders, null, RESTResponse response = restInvoker.invokePOST(certVerifyUrl, certVerifyHeaders, null,
null, certVerifyContent); null, certVerifyContent);
CoreUtils.debugLog(log, "Verify response:", response.getContent()); CoreUtils.debugLog(log, "Verify response:", response.getContent());
@ -135,17 +155,16 @@ public class AuthenticationHandler implements Handler {
log.warn("Unauthorized request for api: " + ctxPath); log.warn("Unauthorized request for api: " + ctxPath);
setFaultCodeAndThrowAxisFault(messageContext, new Exception("Unauthorized!")); setFaultCodeAndThrowAxisFault(messageContext, new Exception("Unauthorized!"));
return InvocationResponse.SUSPEND; return InvocationResponse.SUSPEND;
} catch (Exception e) {
log.error("Error while processing certificate.", e);
setFaultCodeAndThrowAxisFault(messageContext, e);
return InvocationResponse.SUSPEND;
}
} else { } else {
log.warn("Unauthorized request for api: " + ctxPath); log.warn("Unauthorized request for api: " + ctxPath);
setFaultCodeAndThrowAxisFault(messageContext, new Exception("SSL required")); setFaultCodeAndThrowAxisFault(messageContext, new Exception("SSL required"));
return InvocationResponse.SUSPEND; return InvocationResponse.SUSPEND;
} }
} catch (Exception e) {
log.error("Error while processing certificate.", e);
setFaultCodeAndThrowAxisFault(messageContext, e);
return InvocationResponse.SUSPEND;
}
} else { } else {
return InvocationResponse.CONTINUE; return InvocationResponse.CONTINUE;
} }
@ -159,7 +178,7 @@ public class AuthenticationHandler implements Handler {
* @return boolean * @return boolean
*/ */
private boolean isSecuredAPI(MessageContext messageContext) { private boolean isSecuredAPI(MessageContext messageContext) {
if (messageContext.getTransportIn() != null && if (messageContext.getTo() != null && messageContext.getTransportIn() != null &&
messageContext.getTransportIn().getName().toLowerCase().equals(AuthConstants.HTTPS)) { messageContext.getTransportIn().getName().toLowerCase().equals(AuthConstants.HTTPS)) {
for (String path : apiList) { for (String path : apiList) {
if (messageContext.getTo().getAddress().trim().contains(path)) { if (messageContext.getTo().getAddress().trim().contains(path)) {
@ -170,6 +189,55 @@ public class AuthenticationHandler implements Handler {
return false; 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<String, String> drcHeaders = new HashMap<String, String>();
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<String, String> tokenHeaders = new HashMap<String, String>();
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 { private void setFaultCodeAndThrowAxisFault(MessageContext msgContext, Exception e) throws AxisFault {
msgContext.setProperty(AuthConstants.SEC_FAULT, Boolean.TRUE); msgContext.setProperty(AuthConstants.SEC_FAULT, Boolean.TRUE);

@ -21,7 +21,6 @@ public class AuthConstants {
public static final String SEC_FAULT = "SECURITY_VALIDATION_FAILURE"; public static final String SEC_FAULT = "SECURITY_VALIDATION_FAILURE";
public static final String HTTPS = "https"; public static final String HTTPS = "https";
public static final String WSSE = "wsse"; 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 AUTH_CONFIGURATION_FILE_NAME = "api-filter-config.xml";
public static final String API_FILTER_CONFIG_ELEMENT = "apiFilterConfig"; public static final String API_FILTER_CONFIG_ELEMENT = "apiFilterConfig";
public static final String API_LIST_PROPERTY = "apiList"; 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 USERNAME = "username";
public static final String PASSWORD = "password"; public static final String PASSWORD = "password";
public static final String MDM_SIGNATURE = "mdm-signature"; public static final String MDM_SIGNATURE = "mdm-signature";
public static final String IOS = "ios"; public static final String PROXY_MUTUAL_AUTH_HEADER = "proxy-mutual-auth-header";
public static final String ANDROID = "android"; public static final String ENCODED_PEM = "encoded-pem";
} }

Loading…
Cancel
Save