Quantcast
Channel: Sanjeewa Malalgoda's Blog
Viewing all 220 articles
Browse latest View live

How to write sample class mediator to get system property and inject to synapse properties / How to generate response with synapse property using script mediator

$
0
0
Here i have added class mediator code and sample synapse configuration to get carbon server home property. To test this create java project and add following class mediator code file to /repository/components/lib directory and add following synapse configuration to source view.  Then you can invoke created proxy service.

Class mediator code.

package main.java.org.wso2.carbon.custommediator;
import org.apache.synapse.MessageContext;
import org.apache.synapse.core.axis2.Axis2MessageContext;
import org.apache.synapse.mediators.AbstractMediator;
public class SampleCustomMediator extends AbstractMediator {

public boolean mediate(MessageContext synapseMsgContext) {
    String carbonHome = System.getProperty("carbon.home");
    log.info("Carbon Home is : "+carbonHome);
    synapseMsgContext.setProperty("CARBON_HOME", carbonHome);
    return true;
 }
 


Synapse configuration.

 

<proxyname="EchoProxyTest"
          transports="https http"
          startOnLoad="true"
          trace="disable">
  <target>
   <inSequence>
     <classname="main.java.org.wso2.carbon.custommediator.SampleCustomMediator"/>
     <sequencekey="responseTest"/>
   </inSequence>
   <outSequence>
      <send/>
   </outSequence>
 </target>
</proxy>
<sequencename="responseTest">
      <scriptlanguage="js">var carbonHome = mc.getProperty("CARBON_HOME");
      var carbonHomeTest = "sanjeewa";
      mc.setPayloadXML(&lt;serverHome&gt;{carbonHome}&lt;/serverHome&gt;);</script>
      <headername="To"action="remove"/>
      <propertyname="NO_ENTITY_BODY"scope="axis2"action="remove"/>
      <propertyname="RESPONSE"value="true"/>
      <send/>
      <loglevel="full"/>
</sequence>



You can invoke create proxy service by calling following URL
https://130.76.202.98:9443/services/EchoProxyTest

Then you will get following response.
 

<serverHome>/home/sanjeewa/work/packs/wso2esb-4.8.0</serverHome>

Read system property using proxy service deployed in WSO2 ESB

$
0
0
Here i have added sample synapse configuration to get carbon server home property and return it as response. Add this configuration and invoke proxy service. You will get carbon.home as response.





<proxyname="EchoProxyTest"
          transports="https http"
          startOnLoad="true"
          trace="disable">
      <description/>
      <target>
         <inSequence>
            <sequence key="responseTest1"/>
         </inSequence>
         <outSequence>
            <send/>
         </outSequence>
      </target>
   </proxy>
 <sequencename="responseTest1">
      <script language="js">var carbonHome = java.lang.System.getProperty("carbon.home");
      mc.setPayloadXML(&lt;serverHome&gt;{carbonHome}&lt;/serverHome&gt;);</script>
      <headername="To"action="remove"/>
      <propertyname="NO_ENTITY_BODY"scope="axis2"action="remove"/>
      <propertyname="RESPONSE"value="true"/>
      <send/>
      <log level="full"/>
   </sequence>

How to modify JWT to retrieve subscriber details instead of end user - WSO2 API Manager

$
0
0
IN WSO2 API Manager JWT generated per API call. To generate we will use access token coming with the request. From this token we will retrieve token owner(person who generated token).
Once we have token owner, we will retrieve claims associated with that user. In this case we need to get application owner details(person who create application and subscribe to API). We have an extension point to implement claim retriever.

We can find more information from this[1] document. If you need to generate custom claims based on your requirement you need to implement claim retriever class and configure following[2] parameter in api-manager.xml configuration file.
Inside our implementation we need to retrieve application owner and retrieve his claims. For this first we need to get SUBSCRIBER_ID from AM_APPLICATION table by using application Id(we already have it in JWT). Then need to retrieve USER_ID from AM_SUBSCRIBER table by using previously retrieved SUBSCRIBER_ID. Then from that USER_ID we will be able to retrieve claims of Application owner in the same way we do it for end user. Hope this will help you.

[1]https://docs.wso2.com/display/AM170/Passing+Enduser+attributes+to+the+Backend+Using+JWT

[2]<ClaimsRetrieverImplClass>org.wso2.carbon.apimgt.impl.token.DefaultClaimsRetriever</ClaimsRetrieverImplClass>

Enable web service key validation and session affinity - WSO2 API Manager deployment in AWS

$
0
0
In clustered environment following issue can happen if we didn't enabled session affinity.
TID: [0] [AM] [2015-11-01 23:31:42,819] WARN {org.wso2.carbon.apimgt.keymgt.service.thrift.APIKeyValidationServiceImpl} - Invalid session id for thrift authenticator. {org.wso2.carbon.apimgt.keymgt.service.thrift.APIKeyValidationServiceImpl}
TID: [0] [AM] [2015-11-01 23:31:42,820] WARN {org.wso2.carbon.apimgt.gateway.handlers.security.thrift.ThriftKeyValidatorClientPool} - Login failed.. Authenticating again.. {org.wso2.carbon.apimgt.gateway.handlers.security.thrift.ThriftKeyValidatorClientPool}
TID: [0] [AM] [2015-11-01 23:31:42,821] ERROR {org.wso2.carbon.apimgt.gateway.handlers.security.APIAuthenticationHandler} - API authentication failure {org.wso2.carbon.apimgt.gateway.handlers.security.APIAuthenticationHandler}

When API gateway receives API call we do token validation call to key management service running on key management server. First we will authenticate with key management service and then do secure call to validate token. This key management service is running on all API Manager nodes. When client call to validate token it will authenticate with service running in one server and actual validation service call going to other server. To resolve this issue please follow below instructions.

Set following properties in API Manager configuration file and restart servers. With this we will be using web service call between gateway and key manager to validate token. Most of load balancers cannot route thrift messages in session aware way. So we will use web service call for that.


<KeyValidatorClientType>WSClient</KeyValidatorClientType>
<EnableThriftServer>false</EnableThriftServer>
Also you need to configure key management server URL properly in configurations(see following configuration).



<APIKeyManager>
        <ServerURL>https://test.wso2.com:9443/services/&lt;/ServerURL>
To enable session affinity. Enable session affinity and enable application generated session cookies in load balancer level. Also set cookie name as JSESSIONID. Then it will route requests in session aware manner.

API Manager distributed deployment best practices - API gateway Deployment in DMZ and MZ

$
0
0
Normally when we deploy API Manager in different zones we need to follow security related best practices. Here in this post we will briefly describe about API Manager gateway deployment in DMZ and MZ.

How API Gateway and key manager communication happens
In API Manager we have authentication handler to authenticate all incoming requests. From authentication handler we will will initiate token validation flow. We do have extension point to authentication handler. So if you need to implement some custom flow you can write new handler and use it. In key manager side we have exposed web service and thrift service for this(key validation service). We have two options to select when we call key manager from gateway.
01. Web service call.
In this case we will do a web service call from gateway to key manager. For this call we will Https and we will be using transport layer security for this. for this gateway will authenticate with key manager by using configured username/password in api-manager.xml file.
02. Thrift call.
In this case we will do a thrift service call from gateway to key manager. For this call also we will be using transport layer security(for login). And gateway will authenticate with key manager(thrift server) by using configured username/password in api-manager.xml file.

How to secure deployment(API gateway) in DMZ from common attacks
We have configurations files, run time artifacts and required jar file in repository directory.
We can use secure vault(https://docs.wso2.com/display/Carbon420/WSO2+Carbon+Secure+Vault) to protect repository/conf directory. Then attacker will not get sensitive data like user name, passwords and important urls. With this we will be able to recover configurations even if attacker got file system access.
And if we can keep open 8280 and 8243 then we don't need to expose management urls to outside world. So external users cannot use management services perform server side operations.
If we are having API gateway with worker manager separated then, only workers will reside in DMZ. Even if attacker destroyed synapse configuration in worker nodes still manager node and svn repository will have original configurations. So we can easily recover from this type of situation.
And we can enable java security manager to avoid some common form of attacks(jar file modifications etc).

Please see attached image to identify call between MZ and DMZ.








We have few call between MZ and DMZ
Key validation call from gateway to key manager(connect over https).
Token generation request from gateway to key manager(connect over https).
Artifact synchronize call to svn server(connect over https).
Call from gateway to back end services hosted in MZ(connect over https or http).
Cluster communication between workers and manager node(tcp level cluster messages).



How to change logged in user password in WSO2 Carbon based products

$
0
0
If you need to call user admin service and perform this operation you can use following information.
Service URL
https://sanjeewa-ThinkPad-T530:9443/services/UserAdmin

PayLoad

<soapenv:Envelopexmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://org.apache.axis2/xsd">
   <soapenv:Header/>
   <soapenv:Body>
      <xsd:changePasswordByUser>
         <xsd:oldPassword>testsanjeewa</xsd:oldPassword>
         <xsd:newPassword>sanjeewa</xsd:newPassword>
      </xsd:changePasswordByUser>
   </soapenv:Body>
</soapenv:Envelope>
Other possible solution is change password from management console user interface.
Visit following URL https://10.100.1.65:9443/carbon And go to change password window.
Home > Configure > Users and Roles > Change Password

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

$
0
0
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.




How to use custom authentication header and pass it as auth header to back end server(in addition to bearer token).

$
0
0
In this article we will describe how we can use custom authentication header and pass it as auth header to backend server.

You can add a mediation extension [1], and have a custom global sequence in the API gateway which will assign Authorization header the value of your basic authentication.

<sequence name="WSO2AM--Ext--In" xmlns="http://ws.apache.org/ns/synapse"> 
<property name="Authentication" expression="get-property('transport', 'Authentication')"/>
<property name="Authorization" expression="get-property('Authentication')" scope="transport" type="STRING"/>
<property name="Authentication" scope="transport" action="remove" />
</sequence>


In order to add the custom mediation, visit '/repository/deployment/server/synapse-configs/default/sequences' and create an xml file (Ex: global_ext.xml) to contain your mediation extension.
Then include above synapse configuration in that xml. (I have attached the custom global sequence xml here).

When you invoke your Rest API via a RESTclient, configure that client to have a custom header(Ex:Authentication) for your basic authentication credentials and configure 'Authorization' header to contain the bearer token for the API.

So, what will happen will be something like this:
Client (headers: Authorization, Authentication) -> Gateway (drop: Authorization, convert: Authentication-Authorization) -> Backend


[1]https://docs.wso2.com/display/AM150/Adding+a+Mediation+Extension

How to hide actual backend wsdl by providing internal WSDL in WSO2 API Manager

$
0
0
In WSO2 API Manager we can provide wsdl when we create API. And users may be able to access it from UI. When we store API in registry we will rewrite endpoints to match with API created. But still users can type API url and wsdl and hit backend wsdl. For this we can suggest synapse configuration based solution. For this i added filter on top of resource and check request is coming for wsdl. If it contains wsdl url then we can forward request to registry path of internal wsdl. Sometimes editing synapse configurations manually will cause to some problems(when we update through publisher it will discard changes etc). So we normally dont recommend that but in this case we do not have other option. 
 
As a solution for that we can automate this using velosity template file. Then we don't have to do this per each API Manually. For this we can use API name, context and version parameters inside velosity configuration and generate filter according to that. Sample configuration would be something like this. Please note here we should have connection to registry ( some of our clients don't mount registry for gateway). We need to explain limitations of this approach when we reply to client.

<filtersource="get-property('To')"regex=".*?wsdl.*">
<loglevel="custom">
<propertyname="end"expression="get-property('To')"/>
</log>
<send>
<endpoint>
<addressuri="http://10.100.1.65:9763
/registry/resource/_system/governance/apimgt/applicationdata/wsdls/admin--rrr1.0.0.wsdl"
/>

</endpoint>
</send>
</filter>


Server to server communication in WSO2 Carbon based products

$
0
0
Normally for server to server communication we use basic auth as security mechanism(user name and password). But for this communication we can use mutual SSL like mechanism(if need). In this case we will use key store and key store password when we connect to other server. So with this we don't need to store password in text files and login server with user name and password. How ever we need to do code changes to accommodate this change. When we create service client we need to add mutual ssl headers to request. In this[4] article you will find more information about enabling mutual ssl for server to server communication. Other possible alternatives documented in this[5] document.

As these are internal servers (end user is not involved and credentials are passed in internal network), we do not need to change password all time. As we understood internal server to server communication will not expose to external users. External service calls(service calls coming from external users to system) can be secured with token with short life time(oauth). For this we can use API Manager with oauth protocol. And all internal server to server calls happens inside firewall.

Thrift is other common protocol that we can use for server to server communication. Regarding thrift service client implementation, you will find implementation details in following classes[1,2]. Also in this blog[3] post you will find more information about thrift service and client implementation.

[1]trunk/components/apimgt/org.wso2.carbon.apimgt.keymgt/src/main/java/org/wso2/carbon/apimgt/keymgt/service/thrift
[2]trunk/components/apimgt/org.wso2.carbon.apimgt.gateway/src/main/java/org/wso2/carbon/apimgt/gateway/handlers/security/thrift
[3]http://srinathsview.blogspot.com/2011/09/writing-your-first-thrift-service.html
[4]http://java.dzone.com/articles/how-use-mutual-ssl-wso2
[5]http://soasecurity.org/2014/03/25/different-authentication-mechanism-for-wso2-carbon-management-console-and-admin-service-apis/

How to reduce API Manager oauth token table growth and clean old tokens - WSO2 API Manager

$
0
0
With current model token table will not grow fast. AFAIR in API Manager 1.1.0 and 1.2.0 we had this problem due to having multiple active access tokens for same user/app combination. But according to current model we will have only one active access token at given time. And if user requests token again and again we will issue same user access token with update lifetime(do not issue new one). So with that access token table growth should be minimum and will not cause problem.
On the other hand having old access token data will help us to maintain history data. Sometimes we might need to know who is token owner, when it was issues, was it revoked or expired etc(when we analyze logs). In such cases this data will help us.
However if user really need to remove this data we can delete them using db query. We should delete only revoked, expired, inactive tokens(token state) when we have active access token for same consumer key + user combination.

How to generate custom JWT in WSO2 API Manager 1.8.0

$
0
0
In this post we will discuss how to use external implementation for JWT generating logic.
Recently we introduce accessToken to generateToken() method available in AbstractJWTGenerator class which implemented TokenGenerator.
With this change custom JWT generator can generate JWT based on the API access token as well.
We didn't changed method signature of populateStandardClaims(). But followings were changed.

-TokenGenerator.generateToken(APIKeyValidationInfoDTO keyValidationInfoDTO, String apiContext,String version, String accessToken) throws APIManagementException
-AbstractJWTGenerator.buildBody(APIKeyValidationInfoDTO keyValidationInfoDTO, String apiContext, String version, String accessToken)
-AbstractJWTGenerator.populateCustomClaims(APIKeyValidationInfoDTO keyValidationInfoDTO, String apiContext,String version, String accessToken)

New method:
public String generateToken(APIKeyValidationInfoDTO keyValidationInfoDTO, String apiContext,String version, String accessToken) throws APIManagementException.


Sample CustomTokenGenerator code would be something like this. There you can implement your own claim generator.

package org.wso2.carbon.test;

import org.wso2.carbon.apimgt.impl.APIConstants;
import org.wso2.carbon.apimgt.impl.dto.APIKeyValidationInfoDTO;
import org.wso2.carbon.apimgt.impl.token.JWTGenerator;
import org.wso2.carbon.apimgt.api.*;

import java.util.Map;

public class CustomTokenGenerator extends JWTGenerator {

    public Map populateStandardClaims(APIKeyValidationInfoDTO keyValidationInfoDTO, String apiContext, String version)
            throws APIManagementException {
        Map claims = super.populateStandardClaims(keyValidationInfoDTO, apiContext, version);
        boolean isApplicationToken =
                keyValidationInfoDTO.getUserType().equalsIgnoreCase(APIConstants.ACCESS_TOKEN_USER_TYPE_APPLICATION) ? true : false;
        String dialect = getDialectURI();
        if (claims.get(dialect + "/enduser") != null) {
            if (isApplicationToken) {
                claims.put(dialect + "/enduser", "null");
                claims.put(dialect + "/enduserTenantId", "null");
            } else {
                String enduser = claims.get(dialect + "/enduser");
                if (enduser.endsWith("@carbon.super")) {
                    enduser = enduser.replace("@carbon.super", "");
                    claims.put(dialect + "/enduser", enduser);
                }
            }
        }

        return claims;

    }

    public Map populateCustomClaims(APIKeyValidationInfoDTO keyValidationInfoDTO, String apiContext, String version, String accessToken)
            throws APIManagementException {
        System.out.println("************************************************************************Access Token is :"+accessToken );
        boolean isApplicationToken =
                keyValidationInfoDTO.getUserType().equalsIgnoreCase(APIConstants.ACCESS_TOKEN_USER_TYPE_APPLICATION) ? true : false;
        if(getClaimsRetriever() != null) {
            if (isApplicationToken) {
                return null;
            }else {
                return super.populateCustomClaims(keyValidationInfoDTO,apiContext,version,accessToken);
            }
        }

        return null;
    }
}


Build this class and add jar file to /repository/components/lib/ directory of the product.
Then add the element to specify which implementation should be used as the JWTGenerator.
This should come under section in api-manager.xml.
Also JWT generation should be enabled at this time.


<APIConsumerAuthentication>
....
<TokenGeneratorImpl>org.wso2.carbon.test.CustomTokenGenerator</TokenGeneratorImpl>
....
</APIConsumerAuthentication>
Restart the server with :        Linux/Unix :  sh wso2server.sh        Windows    :  wso2server.bat Then when you invoke APIs you will see access token getting printed.

Configure WSO2 API Manager 1.8.0 with reverse proxy (with proxy context path)

$
0
0
Remove current installation of Nginx
sudo apt-get purge nginx nginx-common nginx-full

Install Nginx
sudo apt-get install nginx

Edit configurations
sudo vi /etc/nginx/sites-enabled/default

Create ssl certificates and copy then to ssl folder.
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt

 Sample configuration:

server {

       listen 443;
       ssl on;
       ssl_certificate /etc/nginx/ssl/nginx.crt;
       ssl_certificate_key /etc/nginx/ssl/nginx.key;
       location /apimanager/carbon {
           index index.html;
           proxy_set_header X-Forwarded-Host $host;
           proxy_set_header X-Forwarded-Server $host;
           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
           proxy_pass https://localhost:9443/carbon/;
           proxy_redirect  https://localhost:9443/carbon/  https://localhost/apimanager/carbon/;
           proxy_cookie_path / /apimanager/carbon/;
       }
       location /apimanager/publisher/registry {
           index index.html;
           proxy_set_header X-Forwarded-Host $host;
           proxy_set_header X-Forwarded-Server $host;
           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
           proxy_pass https://localhost:9443/registry;
           proxy_redirect  https://localhost:9443/registry  https://localhost/apimanager/publisher/registry;
           proxy_cookie_path /registry /apimanager/publisher/registry;
       }
      location /apimanager/publisher {
          index index.html;
           proxy_set_header X-Forwarded-Host $host
           proxy_set_header X-Forwarded-Server $host;
           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
           proxy_pass https://localhost:9443/publisher;
           proxy_redirect  https://localhost:9443/publisher  https://localhost/apimanager/publisher;
           proxy_cookie_path /publisher /apimanager/publisher;
      }
      location /apimanager/store {
           index index.html;
           proxy_set_header X-Forwarded-Host $host;
           proxy_set_header X-Forwarded-Server $host;
           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
           proxy_pass https://localhost:9443/store;
           proxy_redirect https://localhost:9443/store https://localhost/apimanager/store;
           proxy_cookie_path /store /apimanager/store;
       }
}

To stop start us following commands

sudo /etc/init.d/nginx start
sudo /etc/init.d/nginx stop

API Manager configurations

Add following API Manager configurations:

In API store edit wso2am-1.8.0/repository/deployment/server/jaggeryapps/store/site/conf/site.json  file and add following.

  "reverseProxy" : {
       "enabled" : true,
       "host" : "localhost",
       "context":"/apimanager/store"
   }


In API publisher edit wso2am-1.8.0/repository/deployment/server/jaggeryapps/publisher/site/conf/site.json  file and add following.

   "reverseProxy" : {
       "enabled" : true,   
       "host" : "localhost",
       "context":"/apimanager/publisher",
   }


Edit /repository/conf/carbon.xml and update following properties.

<HostName>localhost</HostName>
<MgtHostName>localhost</MgtHostName>




Then start API Manager.
Server URLs would be something like this

https://localhost/apimanager/store
https://localhost/apimanager/publisher

How to run WSO2 API Manager 1.8.0 with Java Security Manager enabled

$
0
0
In Java, the Security Manager is available for applications to have various security policies. The Security Manager helps to prevent untrusted code from doing malicious actions on the system.

Here in this post we will see how we can run WSO2 API Manager 1.8.0 with security manager enabled.

To sign the jars, we need a key. We can use the keytool command to generate a key.

sanjeewa@sanjeewa-ThinkPad-T530:~/work/wso2am-1.8.0-1$ keytool -genkey -alias signFiles -keyalg RSA -keystore signkeystore.jks -validity 3650 -dname "CN=Sanjeewa,OU=Engineering, O=WSO2, L=Colombo, ST=Western, C=LK"Enter keystore password: 

Re-enter new password:
Enter key password for
(RETURN if same as keystore password):
Scripts to sign Jars available in product. Create following 2 scripts and grant them required permissions.

signJars.sh script:
    #!/bin/bash
    if [[ ! -d $1 ]]; then
       echo "Please specify a target directory"
       exit 1
    fi
    for jarfile in `find . -type f -iname \*.jar`
    do
      ./signJar.sh $jarfile
    done



signJar.sh script:

    #!/bin/bash
    set -e
    jarfile=$1
    keystore_file="signkeystore.jks"
    keystore_keyalias='signFiles'
    keystore_storepass='wso2123'
    keystore_keypass='wso2123'
    signjar="$JAVA_HOME/bin/jarsigner -sigalg MD5withRSA -digestalg SHA1 -keystore $keystore_file -storepass $keystore_storepass -keypass $keystore_keypass"
    verifyjar="$JAVA_HOME/bin/jarsigner -keystore $keystore_file -verify"
    echo "Signing $jarfile"
    $signjar $jarfile $keystore_keyalias
    echo "Verifying $jarfile"
    $verifyjar $jarfile
    # Check whether the verification is successful.
    if [ $? -eq 1 ]
    then
       echo "Verification failed for $jarfile"
    fi



Then sign all jars using above created scripts
    ./signJars.sh ./repository/ > log

Add following to wso2server.sh file

 -Djava.security.manager=org.wso2.carbon.bootstrap.CarbonSecurityManager \
 -Djava.security.policy=$CARBON_HOME/repository/conf/sec.policy \
 -Drestricted.packages=sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,org.wso2.carbon. \  -Ddenied.system.properties=javax.net.ssl.trustStore,javax.net.ssl.trustStorePassword,denied.system.properties \

Exporting signFiles public key certificate and importing it to wso2carbon.jks

We need to import the signFiles public key certificate to the wso2carbon.jks as the security policy file will be referring the signFiles signer certificate from the wso2carbon.jks (as specified by the first line).

    $ keytool -export -keystore signkeystore.jks -alias signFiles -file sign-cert.cer
    sanjeewa@sanjeewa-ThinkPad-T530:~/work/wso2am-1.8.0-1$ keytool -import -alias signFiles -file sign-cert.cer -keystore repository/resources/security/wso2carbon.jks
    Enter keystore password: 
    Owner: CN=Sanjeewa, OU=Engineering, O=WSO2, L=Colombo, ST=Western, C=LK
    Issuer: CN=Sanjeewa, OU=Engineering, O=WSO2, L=Colombo, ST=Western, C=LK
    Serial number: 5486f3b0
    Valid from: Tue Dec 09 18:35:52 IST 2014 until: Fri Dec 06 18:35:52 IST 2024
    Certificate fingerprints:
    MD5:  54:13:FD:06:6F:C9:A6:BC:EE:DF:73:A9:88:CC:02:EC
    SHA1: AE:37:2A:9E:66:86:12:68:28:88:12:A0:85:50:B1:D1:21:BD:49:52
    Signature algorithm name: SHA1withRSA
    Version: 3
    Trust this certificate? [no]:  yes
    Certificate was added to keystore

Then add following sec.policy file
    keystore "file:${user.dir}/repository/resources/security/wso2carbon.jks", "JKS";

    // ========= Carbon Server Permissions ===================================
    grant {
       // Allow socket connections for any host
       permission java.net.SocketPermission "*:1-65535", "connect,resolve";
       // Allow to read all properties. Use -Ddenied.system.properties in wso2server.sh to restrict properties
       permission java.util.PropertyPermission "*", "read";
       permission java.lang.RuntimePermission "getClassLoader";
       // CarbonContext APIs require this permission
       permission java.lang.management.ManagementPermission "control";
       // Required by any component reading XMLs. For example: org.wso2.carbon.databridge.agent.thrift:4.2.1.
       permission java.lang.RuntimePermission "accessClassInPackage.com.sun.xml.internal.bind.v2.runtime.reflect";
       // Required by org.wso2.carbon.ndatasource.core:4.2.0. This is only necessary after adding above permission.
       permission java.lang.RuntimePermission "accessClassInPackage.com.sun.xml.internal.bind";
     permission java.io.FilePermission "${carbon.home}/repository/deployment/server/jaggeryapps/publisher/localhost/publisher/site/conf/locales/jaggery/locale_en.json", "read,write";
      permission java.io.FilePermission "${carbon.home}/repository/deployment/server/jaggeryapps/publisher/localhost/publisher/site/conf/locales/jaggery/locale_default.json", "read,write";
      permission java.io.FilePermission "${carbon.home}/repository/deployment/server/jaggeryapps/publisher/site/conf/site.json", "read,write";
      permission java.io.FilePermission "${carbon.home}/repository/deployment/server/jaggeryapps/store/localhost/store/site/conf/locales/jaggery/locale_en.json", "read,write";
      permission java.io.FilePermission "${carbon.home}/repository/deployment/server/jaggeryapps/store/localhost/store/site/conf/locales/jaggery/locale_default.json", "read,write";
      permission java.io.FilePermission "${carbon.home}/repository/deployment/server/jaggeryapps/store/site/conf/locales/jaggery/locale_en.json", "read,write";
      permission java.io.FilePermission "${carbon.home}/repository/deployment/server/jaggeryapps/store/site/conf/locales/jaggery/locale_default.json", "read,write";
      permission java.io.FilePermission "${carbon.home}/repository/deployment/server/jaggeryapps/store/site/conf/site.json", "read,write";
       permission javax.management.MBeanServerPermission "findMBeanServer,createMBeanServer";
      permission javax.management.MBeanPermission "-#-[-]", "queryNames";
      permission javax.management.MBeanPermission "sun.management.MemoryImpl#*[java.lang:type=Memory]", "queryNames";
      permission javax.management.MBeanPermission "sun.management.MemoryImpl#*[java.lang:type=Memory]", "getMBeanInfo";
      permission javax.management.MBeanPermission "sun.management.MemoryImpl#*[java.lang:type=Memory]", "getAttribute";
      permission javax.management.MBeanPermission "sun.management.MemoryPoolImpl#*[java.lang:type=MemoryPool,name=*]", "queryNames";
      permission javax.management.MBeanPermission "sun.management.MemoryPoolImpl#*[java.lang:type=MemoryPool,name=*]", "getMBeanInfo";
      permission javax.management.MBeanPermission "sun.management.MemoryPoolImpl#*[java.lang:type=MemoryPool,name=*]", "getAttribute";
      permission javax.management.MBeanPermission "sun.management.GarbageCollectorImpl#*[java.lang:type=GarbageCollector,name=*]", "queryNames";
      permission javax.management.MBeanPermission "sun.management.GarbageCollectorImpl#*[java.lang:type=GarbageCollector,name=*]", "getMBeanInfo";
      permission javax.management.MBeanPermission "sun.management.GarbageCollectorImpl#*[java.lang:type=GarbageCollector,name=*]", "getAttribute";
      permission javax.management.MBeanPermission "sun.management.ClassLoadingImpl#*[java.lang:type=ClassLoading]", "queryNames";
      permission javax.management.MBeanPermission "sun.management.ClassLoadingImpl#*[java.lang:type=ClassLoading]", "getMBeanInfo";
      permission javax.management.MBeanPermission "sun.management.ClassLoadingImpl#*[java.lang:type=ClassLoading]", "getAttribute";
      permission javax.management.MBeanPermission "sun.management.RuntimeImpl#*[java.lang:type=Runtime]", "queryNames";
      permission javax.management.MBeanPermission "sun.management.RuntimeImpl#*[java.lang:type=Runtime]", "getMBeanInfo";
      permission javax.management.MBeanPermission "sun.management.RuntimeImpl#*[java.lang:type=Runtime]", "getAttribute";
      permission javax.management.MBeanPermission "sun.management.ThreadImpl#*[java.lang:type=Threading]", "queryNames";
      permission javax.management.MBeanPermission "sun.management.ThreadImpl#*[java.lang:type=Threading]", "getMBeanInfo";
      permission javax.management.MBeanPermission "sun.management.ThreadImpl#*[java.lang:type=Threading]", "getAttribute";
      permission javax.management.MBeanPermission "com.sun.management.UnixOperatingSystem#*[java.lang:type=OperatingSystem]", "queryNames";
      permission javax.management.MBeanPermission "com.sun.management.UnixOperatingSystem#*[java.lang:type=OperatingSystem]", "getMBeanInfo";
      permission javax.management.MBeanPermission "com.sun.management.UnixOperatingSystem#*[java.lang:type=OperatingSystem]", "getAttribute";
      permission javax.management.MBeanPermission "org.wso2.carbon.caching.impl.CacheMXBeanImpl#-[org.wso2.carbon:type=Cache,*]", "registerMBean";
      permission javax.management.MBeanPermission "org.apache.axis2.transport.base.TransportView#-[org.apache.synapse:Type=Transport,*]", "registerMBean";
      permission javax.management.MBeanPermission "org.apache.axis2.transport.base.TransportView#-[org.apache.axis2:Type=Transport,*]", "registerMBean";
      permission javax.management.MBeanPermission "org.apache.axis2.transport.base.TransportView#-[org.apache.synapse:Type=Transport,*]", "registerMBean";
      permission java.lang.RuntimePermission "modifyThreadGroup";
      permission java.io.FilePermission "${carbon.home}/repository/database", "read";
      permission java.io.FilePermission "${carbon.home}/repository/database/-", "read";
      permission java.io.FilePermission "${carbon.home}/repository/database/-", "write";
      permission java.io.FilePermission "${carbon.home}/repository/database/-", "delete";
    };
    // Trust all super tenant deployed artifacts
    grant codeBase "file:${carbon.home}/repository/deployment/server/-" {
           permission java.security.AllPermission;
    };
    grant codeBase "file:${carbon.home}/lib/tomcat/work/Catalina/localhost/-" {
     permission java.io.FilePermission "/META-INF", "read";
     permission java.io.FilePermission "/META-INF/-", "read";
     permission java.io.FilePermission "-", "read";
     permission org.osgi.framework.AdminPermission "*", "resolve,resource";
     permission java.lang.RuntimePermission "*", "accessClassInPackage.org.apache.jasper.compiler";
    };
    // ========= Platform signed code permissions ===========================
    grant signedBy "signFiles" {
     permission java.security.AllPermission;
    };
    // ========= Granting permissions to webapps ============================
    grant codeBase "file:${carbon.home}/repository/deployment/server/webapps/-" {
       // Required by webapps. For example JSF apps.
       permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
       // Required by webapps. For example JSF apps require this to initialize com.sun.faces.config.ConfigureListener
       permission java.lang.RuntimePermission "setContextClassLoader";
       // Required by webapps to make HttpsURLConnection etc.
       permission java.lang.RuntimePermission "modifyThreadGroup";
       // Required by webapps. For example JSF apps need to invoke annotated methods like @PreDestroy
       permission java.lang.RuntimePermission "accessDeclaredMembers";
       // Required by webapps. For example JSF apps
       permission java.lang.RuntimePermission "accessClassInPackage.org.apache.jasper.compiler";
       // Required by webapps. For example JSF EL
       permission java.lang.RuntimePermission "getClassLoader";
       // Required by CXF app. Needed when invoking services
       permission javax.xml.bind.JAXBPermission "setDatatypeConverter";
       // File reads required by JSF (Sun Mojarra & MyFaces require these)
       // MyFaces has a fix https://issues.apache.org/jira/browse/MYFACES-3590  
       permission java.io.FilePermission "/META-INF", "read";
       permission java.io.FilePermission "/META-INF/-", "read";
       // OSGi permissions are requied to resolve bundles. Required by JSF
       permission org.osgi.framework.AdminPermission "*", "resolve,resource";

    };

Start server



How to write API Manager selenium test case to login publisher and view stats

$
0
0
In this article i will share sample code to login API publisher and view stats dashboard. You can use similar tests to test API Manager stats dash board related functionalities.

Add following source to integration tests and full class name to testings.xml file

import org.testng.Assert;
import org.testng.annotations.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

public class DOJOUIElementTestCase {
    @Test(groups = {"wso2.am"}, description = "APIM stats DOJO element test case")
    public void LoginWithEmailUserNameTestCase() throws Exception {
        WebDriver driver = new FirefoxDriver();
        driver.get("https://localhost:9443/publisher/");
        driver.findElement(By.id("username")).sendKeys("provider1");
        driver.findElement(By.id("pass")).sendKeys("provider1");
        driver.findElement(By.id("loginButton")).click();
        WebDriverWait wait = new WebDriverWait(driver, 10);        wait.until(ExpectedConditions.elementToBeClickable(By.linkText("Statistics")));
        driver.findElement(By.linkText("Statistics")).click();
        driver.findElement(By.linkText("API Response Times")).click();    wait.until(ExpectedConditions.elementToBeClickable(By.id("serviceTimeChart")));
        driver.findElements(By.id("serviceTimeChart")).get(0).click();    wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//div[contains(@class,'dijitTooltipRight')]")));
        WebElement toolTip = driver.findElement(By.xpath("//div[contains(@class,'dijitTooltipRight')]"));
        Assert.assertEquals(toolTip.getText().contains("ms"), true);
        driver.quit();
    }
}

Sample JAX-RS web application to test Application servers for basic vulnerabilities

$
0
0
I have created web application[1] which we can use for security tests. With this rest service we can perform basic security tests like file copy, delete, system property read etc. Also added sample Jmeter test case to verify its functionality. You need to deploy this in tenant space and call rest APIs as follows.

[1]https://github.com/sanjeewa-malalgoda/test-apps/tree/master/security-check


Requests should be send with following format:

HTTP GET - Read file (complete file path)
https://test.com/t/xxx.xxx/webapps/security-check/directFile?fileName=repository/conf/axis2/axis2.xml

HTTP POST - Create file (complete file path)
https://test.com/t/xxx.xxx/webapps/security-check/directFile?fileName=repository/conf/axis2/axis2.xml-dummy

HTTP DELETE - Delete file in Server (complete file path)
https://test.com/t/xxx.xxx/webapps/security-check/directFile?fileName=repository/conf/axis2/axis2.xml-dummy

HTTP GET - Read file (file path from carbon server home)
https://test.com/t/xxx.xxx/webapps/security-check/file?fileName=repository/conf/axis2/axis2.xml

HTTP POST - Create file (file path from carbon server home)
https://test.com/t/xxx.xxx/webapps/security-check/file?fileName=repository/conf/axis2/axis2.xml-dummy

HTTP DELETE - Delete file in Server (file path from carbon server home)
https://test.com/t/xxx.xxx/webapps/security-check/file?fileName=repository/conf/axis2/axis2.xml-dummy

HTTP GET - Read system property
https://test.com/t/xxx.xxx/webapps/security-check/systemProperty/java.home

HTTP POST - Copy files in server using carbon Utility methods
https://test.com/t/xxx.xxx/webapps/security-check/fileCopy?source=repository/conf/axis2/axis2.xml&destination=repository/conf/axis2/axis2.xml-dummy

HTTP POST - Delete files in server using carbon Utils
https://test.com/t/xxx.xxx/webapps/security-check/fileDelete?path=repository/conf/axis2/axis2.xml_PT

HTTP POST - Get registryDBConfig as string
https://test.com/t/xxx.xxx/webapps/security-check/registryDBConfig

HTTP POST - Get userManagerDBConfig config as string
https://test.com/t/xxx.xxx/webapps/security-check/userManagerDBConfig

HTTP GET - Get network configs as string
https://test.com/t/xxx.xxx/webapps/security-check/networkConfigs

HTTP GET - Get server configuration as string
https://test.com/t/xxx.xxx/webapps/security-check/serverConfiguration

HTTP POST - Get network configs as string
https://test.com/t/xxx.xxx/webapps/security-check/networkConfigs?hostName=test.org&mgtHostName=test1.org

============Following operations will not be covered using Java security Manager=========
HTTP POST - Generate OOM
https://test.com/t/xxx.xxx/webapps/security-check/memory?operation=oom

HTTP POST - Generate high CPU
https://test.com/t/xxx.xxx/webapps/security-check/memory?operation=cpu

HTTP POST - Generate system call
https://test.com/t/xxx.xxx/webapps/security-check/memory?operation=kill

How to use account lock/ unlock feature in WSO2 API Manager 1.6.0

$
0
0
Create new user named testuser. Grant subscriber permission.

Then install required features to APIM 1.6.0 and restarted server

Then locked test user as follows.
Goto claim management UI and make accountLocked to support by default claim


Then go to users and select required user and lock account


I enabled following property in identity-mgt.properties file.
Identity.Listener.Enable=true 

I restarted server to make sure this is not claim cache issue. Now this account is locked and will not be able to use anymore.


How to implement custom JWT generator and custom claim retriever and link them in WSO2 API Manager 1.8.0

$
0
0
Here in this post we will discuss how to use custom code for JWT generation and Claims retrieve logic. I have explained custom JWT generation with API Manager 1.8.0 in this post(http://sanjeewamalalgoda.blogspot.com/2014/12/how-to-generate-custom-jwt-in-wso2-api.html). Moving forward we will see how we can call custom claim retrieve method from JWT generator implementation. Once everything configured properly you will see JWT similar to below.

{"iss":"wso2.org/products/am","exp":"1418619165375","http://wso2.org/claims/subscriber":"admin","http://wso2.org/claims/applicationid":"2","http://wso2.org/claims/applicationname":"DefaultApplication","http://wso2.org/claims/applicationtier":"Unlimited","http://wso2.org/claims/apicontext":"/testam/sanjeewa","http://wso2.org/claims/version":"1.0.0","http://wso2.org/claims/tier":"Bronze","http://wso2.org/claims/keytype":"PRODUCTION","http://wso2.org/claims/usertype":"APPLICATION_USER","http://wso2.org/claims/enduser":"admin","http://wso2.org/claims/enduserTenantId":"-1234","current_timestamp":"1418618265391","messge":"This is custom JWT"}

As you can see current_timestamp and message properties will be there in JWT with customized JWT generator code.

public Map populateCustomClaims(APIKeyValidationInfoDTO keyValidationInfoDTO, String apiContext, String version, String accessToken)
            throws APIManagementException {
        Long time = System.currentTimeMillis();
        String text = "This is custom JWT";
        Map map = new HashMap();
        map.put("current_timestamp", time.toString());
        map.put("messge" , text);
//If need you can generate access token based claims and embedded them to map.
return map;
}

Also if need to generate custom claims based on access token you can extend org.wso2.carbon.apimgt.impl.token.ClaimsRetriever class and implement method for that as follows.

 public SortedMap getClaims(String endUserName, String accessToken) throws APIManagementException {
 //you implementation should go here
 }

Then call it inside populateCustomClaims as follows.

   public Map populateCustomClaims(APIKeyValidationInfoDTO keyValidationInfoDTO, String apiContext, String version, String accessToken)
            throws APIManagementException {
        CustomClaimsRetriever claimsRetriever = (CustomClaimsRetriever)getClaimsRetriever();
        if (claimsRetriever != null) {
            String tenantAwareUserName = keyValidationInfoDTO.getEndUserName();

            if (MultitenantConstants.SUPER_TENANT_ID == APIUtil.getTenantId(tenantAwareUserName)) {
                tenantAwareUserName = MultitenantUtils.getTenantAwareUsername(tenantAwareUserName);
            }

            try {
                //Call getClaims method implemented in custom claim retriever class
                return claimsRetriever.getClaims(tenantAwareUserName,accessToken);

            } catch (Exception e) {
            }
        }
        return null;
    }
You can download complete sample from this URL(Sample Code).

How to use two layer throttling in WSO2 API Manager

$
0
0

Create new tier definitions


Here in this post i will discuss how we can use two throttling policies at a given time for single API.When we have complex use cases we might need to apply different policies at same time.
Below table shows how throttling policies are defined.

Tier
throttle-l1
throttling-l2
Free
300 per month
5 per 3 min
Silver
2000 per month
1 per 5 sec
Gold - Unlimited
unlimited
unlimited


As we need to engage two throttling layers, we will add two throttling tier definitions and and engage them to the API.
In order to do that edit (API definition synapse configuration file)

Ex: AM_HOME/repository/deployment/server/synapse-configs/default/api/admin--animal_v1.0.0.xml file to with the following content

<api xmlns="http://ws.apache.org/ns/synapse"name="admin--animal" context="/animal"version="1.0.0"version-type="url">
   .
   .
   .
   .
          <handlers>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.security.APIAuthenticationHandler"/>
   <handler class="org.wso2.carbon.apimgt.gateway.handlers.throttling.APIThrottleHandler">
           <propertyname="id"value="B"/>
           <propertyname="policyKey"value="gov:/apimgt/applicationdata/throttling-l2.xm"/>
               </handler>
       <handler class="org.wso2.carbon.apimgt.gateway.handlers.throttling.APIThrottleHandler">
           <propertyname="id"value="A"/>
           <propertyname="policyKey"value="gov:/apimgt/applicationdata/tiers.xml"/>
               </handler>
   .
   .
   .
   .
       </handlers>
   .
   .
   .
   </api>


Two layer Throttling
Here we will use two layer throttling to achieve 2 policies for each role(free, silver, gold). Then we will engage them to API with different keys. So both of them will execute in runtime sequentially. In this case you need to replace tiers.xml file in gov:/apimgt/applicationdata/tiers.xml path of gov registry.


1) Copy throttling-l1.xml(create file with following contents) to GOV_REG/apimgt/applicationdata/tiers.xml
2) Copy throttling-l2.xml(create file with following contents) to GOV_REG/apimgt/applicationdata/throttling-l2.xml

(NOTE : GOV_REG is the governance registry root in Carbon console )

Throttling configurations - Policy 01(throttling-l1.xml)

<wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
           xmlns:throttle="http://www.wso2.org/products/wso2commons/throttle">
   <throttle:MediatorThrottleAssertion>
       <wsp:Policy>
           <throttle:ID throttle:type="ROLE">Gold</throttle:ID>
           <wsp:Policy>
               <throttle:Control>
                   <wsp:Policy>
                       <throttle:MaximumCount>20</throttle:MaximumCount>
                       <throttle:UnitTime>60000</throttle:UnitTime>
                   </wsp:Policy>
               </throttle:Control>
           </wsp:Policy>
       </wsp:Policy>
       <wsp:Policy>
           <throttle:ID throttle:type="ROLE">Silver</throttle:ID>
           <wsp:Policy>
               <throttle:Control>
                   <wsp:Policy>
                       <throttle:MaximumCount>2000</throttle:MaximumCount>
                       <throttle:UnitTime>2592000000</throttle:UnitTime>
                   </wsp:Policy>
               </throttle:Control>
           </wsp:Policy>
       </wsp:Policy>
       <wsp:Policy>
           <throttle:ID throttle:type="ROLE">free</throttle:ID>
           <wsp:Policy>
               <throttle:Control>
                   <wsp:Policy>
                       <throttle:MaximumCount>300</throttle:MaximumCount>
                       <throttle:UnitTime>2592000000</throttle:UnitTime>
                   </wsp:Policy>
               </throttle:Control>
           </wsp:Policy>
       </wsp:Policy>
       <wsp:Policy>
           <throttle:ID throttle:type="ROLE">Unauthenticated</throttle:ID>
           <wsp:Policy>
               <throttle:Control>
                   <wsp:Policy>
                       <throttle:MaximumCount>60</throttle:MaximumCount>
                       <throttle:UnitTime>60000</throttle:UnitTime>
                   </wsp:Policy>
               </throttle:Control>
           </wsp:Policy>
       </wsp:Policy>
   </throttle:MediatorThrottleAssertion>
</wsp:Policy>



Policy 02(throttling-l2.xml)

<wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
           xmlns:throttle="http://www.wso2.org/products/wso2commons/throttle">
   <throttle:MediatorThrottleAssertion>
       <wsp:Policy>
           <throttle:ID throttle:type="ROLE">Gold</throttle:ID>
           <wsp:Policy>
               <throttle:Control>
                   <wsp:Policy>
                       <throttle:MaximumCount>20</throttle:MaximumCount>
                       <throttle:UnitTime>60000</throttle:UnitTime>
                   </wsp:Policy>
               </throttle:Control>
           </wsp:Policy>
       </wsp:Policy>
       <wsp:Policy>
           <throttle:ID throttle:type="ROLE">Silver</throttle:ID>
           <wsp:Policy>
               <throttle:Control>
                   <wsp:Policy>
                       <throttle:MaximumCount>1</throttle:MaximumCount>
                       <throttle:UnitTime>5000</throttle:UnitTime>
                   </wsp:Policy>
               </throttle:Control>
           </wsp:Policy>
       </wsp:Policy>
       <wsp:Policy>
           <throttle:ID throttle:type="ROLE">Free</throttle:ID>
           <wsp:Policy>
               <throttle:Control>
                   <wsp:Policy>
                       <throttle:MaximumCount>5</throttle:MaximumCount>
                       <throttle:UnitTime>180000</throttle:UnitTime>
                   </wsp:Policy>
               </throttle:Control>
           </wsp:Policy>
       </wsp:Policy>
       <wsp:Policy>
           <throttle:ID throttle:type="ROLE">Unauthenticated</throttle:ID>
           <wsp:Policy>
               <throttle:Control>
                   <wsp:Policy>
                       <throttle:MaximumCount>60</throttle:MaximumCount>
                       <throttle:UnitTime>60000</throttle:UnitTime>
                   </wsp:Policy>
               </throttle:Control>
           </wsp:Policy>
       </wsp:Policy>
   </throttle:MediatorThrottleAssertion>
</wsp:Policy>



How to get custom error messages for authentication faliures in WSO2 API Manager 1.8.0

$
0
0
Here in this post i will discuss how we can generate custom error messages for auth failures. If you need to retrieve message in application/vnd.error+json format you need to add following parameter to _auth_failure_handler_.xml sequence file.

<propertyname="error_message_type"value="application/vnd.error+json"/>

And also we need to have message builders/formatter defined in axis2.xml file to map this message type. If you plan to use JSON formatter please use following configuration(assume you create message according to given template).
<messageFormatter contentType="application/vnd.error+json"
class="org.apache.axis2.json.JSONMessageFormatter"/>
Viewing all 220 articles
Browse latest View live