Friday, November 14, 2014

How to enable mutual SSL connection between WSO2 API Manager gateway and key manager

In WSO2 API Manager we will do service calls from gateway to key manager to validate tokens.
For this we will use key validation client. Lets add following code and build jar file.


package org.wso2.carbon.apimgt.gateway.handlers.security.keys;
import edu.emory.mathcs.backport.java.util.Arrays;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axiom.om.util.AXIOMUtil;
import org.apache.axiom.soap.SOAPHeaderBlock;
import org.apache.axis2.AxisFault;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.context.ServiceContext;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.commons.httpclient.Header;
import org.wso2.carbon.apimgt.api.model.URITemplate;
import org.wso2.carbon.apimgt.gateway.handlers.security.APISecurityConstants;
import org.wso2.carbon.apimgt.gateway.handlers.security.APISecurityException;
import org.wso2.carbon.apimgt.gateway.internal.ServiceReferenceHolder;
import org.wso2.carbon.apimgt.impl.APIConstants;
import org.wso2.carbon.apimgt.impl.APIManagerConfiguration;
import org.wso2.carbon.apimgt.impl.dto.APIKeyValidationInfoDTO;
import org.wso2.carbon.apimgt.keymgt.stub.validator.APIKeyValidationServiceAPIManagementException;
import org.wso2.carbon.apimgt.keymgt.stub.validator.APIKeyValidationServiceStub;
import org.wso2.carbon.utils.CarbonUtils;
import javax.xml.namespace.QName;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

public class APIKeyValidatorClient {

private static final int TIMEOUT_IN_MILLIS = 15 * 60 * 1000;
private APIKeyValidationServiceStub clientStub;
private String username;
private String password;
private String cookie;

public APIKeyValidatorClient() throws APISecurityException {
APIManagerConfiguration config = ServiceReferenceHolder.getInstance().getAPIManagerConfiguration();
String serviceURL = config.getFirstProperty(APIConstants.API_KEY_MANAGER_URL);
// username = config.getFirstProperty(APIConstants.API_KEY_MANAGER_USERNAME);
// password = config.getFirstProperty(APIConstants.API_KEY_MANAGER_PASSWORD);
/* if (serviceURL == null || username == null || password == null) {
throw new APISecurityException(APISecurityConstants.API_AUTH_GENERAL_ERROR,
"Required connection details for the key management server not provided");
}*/
try {

ConfigurationContext ctx = ConfigurationContextFactory.createConfigurationContextFromFileSystem(null, null);

clientStub = new APIKeyValidationServiceStub(ctx, serviceURL + "APIKeyValidationService");

ServiceClient client = clientStub._getServiceClient();

setMutualAuthHeader(client,"admin");

Options options = client.getOptions();

options.setTimeOutInMilliSeconds(TIMEOUT_IN_MILLIS);

options.setProperty(HTTPConstants.SO_TIMEOUT, TIMEOUT_IN_MILLIS);

options.setProperty(HTTPConstants.CONNECTION_TIMEOUT, TIMEOUT_IN_MILLIS);

options.setCallTransportCleanup(true);

options.setManageSession(true);

} catch (AxisFault axisFault) {

throw new APISecurityException(APISecurityConstants.API_AUTH_GENERAL_ERROR,

"Error while initializing the API key validation stub", axisFault);

} catch (Exception e) {

e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.

}

}
public APIKeyValidationInfoDTO getAPIKeyData(String context, String apiVersion, String apiKey,
String requiredAuthenticationLevel, String clientDomain,
String matchingResource, String httpVerb) throws APISecurityException {
// CarbonUtils.setBasicAccessSecurityHeaders(username, password,
// true, clientStub._getServiceClient());
if (cookie != null) {
clientStub._getServiceClient().getOptions().setProperty(HTTPConstants.COOKIE_STRING, cookie);
}
try {
List headerList = (List)clientStub._getServiceClient().getOptions().getProperty(org.apache.axis2.transport.http.HTTPConstants.HTTP_HEADERS);
Map headers = (Map) MessageContext.getCurrentMessageContext().getProperty(
org.apache.axis2.context.MessageContext.TRANSPORT_HEADERS);
if (headers != null && headers.get("activityID")!=null) {
headerList.add(new Header("activityID", (String)headers.get("activityID")));
}
clientStub._getServiceClient().getOptions().setProperty(org.apache.axis2.transport.http.HTTPConstants.HTTP_HEADERS, headerList);
org.wso2.carbon.apimgt.impl.dto.xsd.APIKeyValidationInfoDTO dto =
clientStub.validateKey(context, apiVersion, apiKey,requiredAuthenticationLevel, clientDomain,
matchingResource, httpVerb);
ServiceContext serviceContext = clientStub.
_getServiceClient().getLastOperationContext().getServiceContext();
cookie = (String) serviceContext.getProperty(HTTPConstants.COOKIE_STRING);
return toDTO(dto);
}
catch (APIKeyValidationServiceAPIManagementException ex){

throw new APISecurityException(APISecurityConstants.API_AUTH_FORBIDDEN,
"Resource forbidden", ex);
}catch (Exception e) {
throw new APISecurityException(APISecurityConstants.API_AUTH_GENERAL_ERROR,
"Error while accessing backend services for API key validation", e);
}
}
private APIKeyValidationInfoDTO toDTO(
org.wso2.carbon.apimgt.impl.dto.xsd.APIKeyValidationInfoDTO generatedDto) {
APIKeyValidationInfoDTO dto = new APIKeyValidationInfoDTO();
dto.setSubscriber(generatedDto.getSubscriber());
dto.setAuthorized(generatedDto.getAuthorized());
dto.setTier(generatedDto.getTier());
dto.setType(generatedDto.getType());
dto.setEndUserToken(generatedDto.getEndUserToken());
dto.setEndUserName(generatedDto.getEndUserName());
dto.setApplicationName(generatedDto.getApplicationName());
dto.setEndUserName(generatedDto.getEndUserName());
dto.setConsumerKey(generatedDto.getConsumerKey());
dto.setValidationStatus(generatedDto.getValidationStatus());
dto.setApplicationId(generatedDto.getApplicationId());
dto.setApplicationTier(generatedDto.getApplicationTier());
dto.setApiPublisher(generatedDto.getApiPublisher());
dto.setApiName(generatedDto.getApiName());
dto.setScopes(generatedDto.getScopes() == null ? null : new HashSet(Arrays.asList(generatedDto.getScopes())));
return dto;
}
public ArrayList getAllURITemplates(String context, String apiVersion
) throws APISecurityException {

// CarbonUtils.setBasicAccessSecurityHeaders(username, password,
// true, clientStub._getServiceClient());
if (cookie != null) {
clientStub._getServiceClient().getOptions().setProperty(HTTPConstants.COOKIE_STRING, cookie);
}
try {
org.wso2.carbon.apimgt.api.model.xsd.URITemplate[] dto =
clientStub.getAllURITemplates(context, apiVersion);
ServiceContext serviceContext = clientStub.
_getServiceClient().getLastOperationContext().getServiceContext();
cookie = (String) serviceContext.getProperty(HTTPConstants.COOKIE_STRING);
ArrayList templates = new ArrayList();
for (org.wso2.carbon.apimgt.api.model.xsd.URITemplate aDto : dto) {
URITemplate temp = toTemplates(aDto);
templates.add(temp);
}
return templates;
} catch (Exception e) {
throw new APISecurityException(APISecurityConstants.API_AUTH_GENERAL_ERROR,
"Error while accessing backend services for API key validation", e);
}
}
private URITemplate toTemplates(
org.wso2.carbon.apimgt.api.model.xsd.URITemplate dto) {
URITemplate template = new URITemplate();
template.setAuthType(dto.getAuthType());
template.setHTTPVerb(dto.getHTTPVerb());
template.setResourceSandboxURI(dto.getResourceSandboxURI());
template.setUriTemplate(dto.getUriTemplate());
template.setThrottlingTier(dto.getThrottlingTier());
return template;
}
private static void setMutualAuthHeader(ServiceClient serviceClient, String username) throws Exception {
OMNamespace omNamespace =
OMAbstractFactory.getOMFactory().createOMNamespace("http://mutualssl.carbon.wso2.org", "m");
SOAPHeaderBlock mutualsslHeader = OMAbstractFactory.getSOAP12Factory().createSOAPHeaderBlock("UserName", omNamespace);
mutualsslHeader.setText(username);
mutualsslHeader.setMustUnderstand("0");
serviceClient.addHeader(mutualsslHeader);
}
}


Then once you build jar copy jar file to API Manager
 cp target/org.wso2.carbon.apimgt.gateway-1.2.2.jar /home/sanjeewa/work/170deployment/newdep/test/wso2am-1.7.0-1/repository/components/plugins/org.wso2.carbon.apimgt.gateway_1.2.2.jar


You should share same trust store or need to export cert to gateway from key manager.

Then enable SSL in WSO2 server. Add following to wso2server.sh

    -Djavax.net.ssl.keyStore="$CARBON_HOME/repository/resources/security/wso2carbon.jks" \
    -Djavax.net.ssl.keyStorePassword="wso2carbon" \
    -Djavax.net.ssl.trustStore="$CARBON_HOME/repository/resources/security/client-truststore.jks" \
    -Djavax.net.ssl.trustStorePassword="wso2carbon" \
    -Djavax.net.ssl.keyAlias="wso2carbon" \


This custom authenticator to makes Identity Server compatible with mutual ssl, so you would need to download it too. You could find the source code of the authenticator from here(https://svn.wso2.org/repos/wso2/carbon/platform/branches/turing/components/authenticators/mutual-ssl-authenticator/4.2.0/).

Build above mentioned code and copy custom authenticator to /repository/components/dropins/ folder which is handling the mutual authentication in the server backend. This should copied to key manager node.

Then restart both servers by pointing gateway to use key manager as key management service.

Invoke APIs and you are now connected to key manager from gateway using mutual ssl. To verify this you can put wrong credentials in gateway side and restart server.




1 comment: