Thursday, May 25, 2017

CORS support from WSO2 API Manager 2.0.0

Cross-origin resource sharing (CORS) is a mechanism that allows restricted resources  on a web page to be requested from another domain outside the domain from which the first restricted resource was served.

For example, an HTML page of a web application served from http://domain-a.com makes an <img src >  request for a different domain as 'domain-b.com' to get an image via an API request. 
For security reasons, browsers restrict cross-origin HTTP requests initiated from within scripts as in above example and only allows to make HTTP requests to its own domain. To avoid this limitation modern browsers have been used CORS standard to allow cross domain requests. Modern browsers use CORS in an API container - such as XMLHttpRequest or Fetch - to mitigate risks of cross-origin HTTP requests.Thing to  note is it's not only sufficient that the browsers handle client side of cross-origin sharing,but also the servers from which these resources getting need to handle server side cross-origin sharing. WSO2 API Manager is fully capable of handling cross-origin sharing for its exposed APIs from gateway.This feature was there in WSO2 API Manager from 1 .x version series and in 2.x onwards it has more improved.
Let's first start with understanding more about the CORS protocol.
What's CORS
The CORS protocol consists of a set of headers that indicates whether a response can be shared cross-origin.The CORS specification distinguishes two different requests done from browser.
1. Simple requests- A cross origin request from browser which a HTTP GET,HEAD or POST [with content-type text/plain, application/x-www-form-urlencoded and multipart/form-data.]
2. Preflighted requests- A cross origin request from browser other than above simple request type will do an additional request with HTTP OPTIONS method to check the resource server understand about cross-domain requests.
Note,if you add Authentication header to simple requests,those will become preflighted ones.
With above two types of requests,the client [browser] and the server will exchange a set of specific headers for cross-domain requests as below.
  1. Origin: this header is used by the client to specify which domain the request is executed from. The server uses this to allow/not, the cross-domain request.
  2. Access-Control-Request-Method: with the preflighted requests, the OPTIONS request  from client sends this header to check if the target HTTP method is allowed for cross-domain requests by the server.
  3. Access-Control-Request-Headers: with the preflighted requests, the OPTIONS request sends this header to check if headers are allowed for the target method  of cross-domain requests.
  4. Access-Control-Allow-Credentials: this specifies if credentials are supported for cross-domain requests.
  5. Access-Control-Allow-Methods: the server uses this header to acknowledge client which HTTP verbs are allowed for cross domain request. This is typically included in the response headers from server for preflighted requests.
  6. Access-Control-Allow-Origin: the server uses this header to acknowledge client which domains are authorized for the request.
  7. Access-Control-Allow-Headers: the server uses this header to tell which headers are allowed for therequest. This is typically included in the response headers from server for preflighted requests.

WSO2 API Manager support for CORS

The above requirement mostly came with the web application developers who used WSO2 API Manager deployed API resources in their web applications.Most of the time,since the WSO2 API Manager domain and web application domain is different,when accessing such API resources from browser based web applications,support for CORS specification was identified as an essential feature.
By default,WSO2 API Manager handle setting CORS headers in it's gateway component itself without passing the CORS requests to back-end to handle CORS scenario.
There's a synapse based handler called CORSRequestHandler which will be handle CORS support for each API invocation.
The flow would be as below for default API invocations.

default flow


When an API request comes to APIM gateway ,the defined  CORSHandler in each API will be executed in request and response flow.By default when create APIs from API Publisher,the 'OPTIONS' resource is hidden to defined in API resource section as below.


If an API creator specifically want to handle the CORS preflight call from backend,instead APIM gateway;he can click on 'More' section in design tab as in above image and specifically select the 'OPTIONS' resource as an API resource.Else,if the API creator didn't select the 'OPTIONS' verb as an API resource,the CORS  will be handle by APIM gateway itself;as shows in above image flow.At the request path,CORS handler validate the incoming request method first.If it's an 'options' call,it checks the synapse API xml contains a resource for 'OPTIONS'.If not,the CORS Handler will set the CORS specific headers Access-Control-Allow-Methods,Access-Control-Allow-Headers,Access-Control-Allow-Origin from gateway itself and pass back the response code as 200 with the CORS headers to the client.Then client will initiate the actual cross domain request with specific HTTP method and it'll process as in above image 'default flow'.
If the API creator want to handle CORS from the actual backend,then he can specifically define the 'OPTIONS' verb at API creation time and at the run time flow will be as below.

How WSO2 APIM Gateway set CORS headers
From API Manager 2.0 onwards,API creators can define Access-Control-Allow-xx headers per API from API Publisher or globally from api-manager.xml   config section as in previous releases.
Add CORS headers per API at API creation time
At runtime ,when an API request come to gateway,with CORS support feature of gateway,the Access-Control allow headers will be set with below validations.
  1. Access-Control-Allow-OriginAPI gateway checks if the incoming request contains a header as 'Origin' and if yes,it'll compare that header value with the  'Access-Control-Allow-Origin' value defined in CORS configuration per API/globally in APIM side.If that origin header is defined in APIM side under CORS config section also,then return back that origin header value as Access-Control-Allow-Origin.Else if the request doesn't send an origin header and if in APIM side Access-Control-Allow-Origin is defined as '*',then APIM gateway will return the Access-Control-Allow-Origin header as '*'.
  2. Access-Control-Allow-Methods: APIM gateway checks if the particular API specific CORS config has defined such value or in api-manager.xml  CORS config section this value is defined.If yes,then match with the actual defined API resource methods in that API and return only the matched method names as Access-Control-Allow-Methods response header.
  3. Access-Control-Allow-Headers: APIM gateway will check if the particular API's CORS configuration/globally has defined a value for Access-Control-Allow-Headers,if yes,respond to client with that value as 'Access-Control-Allow-Headers' header.
  4. Access-Control-Allow-CredentialsAPIM gateway will check if the particular API's CORS configuration/globally has defined a value for Access-Control-Allow-Credentials,if yes and if it set as false,gateway will directly respond to client with that value as 'Access-Control-Allow-Credentials' header.If that value set as true in CORS configurations of APIM side,there's a check to see the value of Access-Control-Allow-Origin in gateway side.If it's not '*',then respond to client with 'Access-Control-Allow-Credentials' header as true.Else as false.
Hope,now you'll be have a basic understanding about how CORS works and how WSO2 API Manager supports it. For more info,refer





Thursday, March 10, 2016

Sharing applications and subscriptions across multiple application developers through WSO2 API Store



In previous WSO2 APIM versions before 1.9.0 version,only the application developer who logs into APIStore can view/manage his applications and subscriptions.But there was a requirement arose mainly due to following two reasons;

-- What if there’s a group of employees in an organization worked as developers for an application and how all those user group could get access to same subscription/application.

--  What if the APIStore logged in developer left the organization and organization want to manage his created subscriptions in-order to manage the developed applications under organization name and only prohibit the left developer of accessing those.

Since above two requirements are really valid in an app development organization perspective ,we have introduced the feature of sharing applications and subscriptions across user groups from APIM 1.9.0 version onwards. The API Manager provides facility to users of a specific logical group to view each other's' applications and subscriptions.  

We have written this feature with the capability to extend it depend on an organization requirement.As the attribute to define the logical user group will be vary based on organizations.For example:

1)In one organization,sharing applications and subscriptions need to be control based on user roles

2) In another scenario,an APIStore can be run as a common APIStore across multiple organizational users.And in that,user grouping has to be done based on organization attribute.

Because of above facts,the flow how the sharing apps/subscriptions flow is as below.


  1. An app developer of an organization tries to login to APIStore
  2. Then in the underlying APIM code,it checks,if  that APIStore server’s api-manager.xml have the config <GroupingExtractor> enabled and if a custom java class implementation defined inside it.
  3. If so,that java class implementation will run and a group ID for logged in user will be set.
  4. Once the app developer logged in and try to access ‘My Applications’ page and ‘My subscriptions’ page,from the underlying code,it’ll return all the database saved applications & subscriptions based on the user’s ‘Group ID’.
With above approach,the applications and subscriptions are shared based on defined ‘Group ID’ from the custom implementation defined in <GroupingExtractor> of api-manager.xml.
By default,we are shipping a sample java implementation as “org.wso2.carbon.apimgt.impl.DefaultGroupIDExtractorImpl” for this feature to consider the organization name which a signup user give at the time he sign up to the API Store as the group ID. From the custom java implementation,it extracts the claim http://wso2.org/claims/organization of the user who tries to login and uses the value specified in that claim as the group ID. This way, all users who specify the same organization name belong to the same group and therefore, can view each other's' subscriptions and applications. 
For more information on default implementation on sharing subscriptions and applications,please refer; https://docs.wso2.com/display/AM190/Sharing+Applications+and+Subscriptions
In a real organization,the requirement can be bit different.The API Manager also provides flexibility to change this default group id extracting implementation.
From this blog-post,I’ll explain how to write the group id extracting extension based on below use-case.

Requirement
An organization want to share subscriptions & applications based on user roles of the organization.They have disabled ‘signup’ option for users to access APIStore and their administrator is giving rights to users to access the APIStore. Basically the application developers of that organization can be categorized in-to two role levels.
  1. Application developers with ‘manager’ role
These developers control production environment deployed mobile applications subscriptions through API Store
2. Application developers with ‘dev’ role
These developers control testing environment deployed mobile applications subscriptions through API Store 
Requirement is to share the applications and subscriptions across these two roles separately.

Solution
Above can be achieved through writing a custom Grouping Extractor class to set ‘Group ID’ based on user roles.
1. First write a java class with implementing the interface org.wso2.carbon.apimgt.api.LoginPostExecutor interface  and make it as a maven module.
2. Then implement the method  logic for ‘getGroupingIdentifiers()’ of the interface.
In this method,it has to extract two separate ‘Group ID’s for users having ‘manager’ role and users having ‘dev’ role. Below is a written sample logic for similar requirement with implementing this method.You can find the complete code from here.

   public String getGroupingIdentifiers(String loginResponse) {
        JSONObject obj;
        String username = null;
        String groupId = null;
        try {
            obj = new JSONObject(loginResponse);
            //Extract the username from login response
            username = (String) obj.get("user");
            loadConfiguration();
             /*Create client for RemoteUserStoreManagerService and perform user management operation*/
            RoleBasedGroupingExtractor extractor = new RoleBasedGroupingExtractor(true);
            //create web service client for userStoreManager
            extractor.createRemoteUserStoreManager();
            //Get the roles of the user
            String[] roles = extractor.getRolesOfUser(username);
            if (roles != null) {//If user has roles
                //Match the roles to check either he/she is from manager/dev role
                for (String role : roles) {
                    if (Constants.MANAGER_ROLE.equals(role)) {
                        //Set the group id as role name
                        groupId = Constants.MANAGER_GROUP;
                    } else if (Constants.ADMIN_ROLE.equals(role)) {
                        //Set the group id as role name
                        groupId = Constants.ADMIN_GROUP;
                    }
                }
            }

        } catch (JSONException e) {
            log.error("Exception occurred while trying to get group Identifier from login response");
        } catch (org.wso2.carbon.user.api.UserStoreException e) {
            log.error("Error while checking user existence for " + username);
        } catch (IOException e) {
            log.error("IO Exception occurred while trying to get group Identifier from login response");
        } catch (Exception e) {
            log.error("Exception occurred while trying to get group Identifier from login response");
        }
        //return the group id
        return groupId;
    }
3.  Build the java maven module and copy the jar into AM_Home/repository/components/lib folder.
4. Then open APIStore running AM server’s api-manager.xml located at {AM_Home}/repository/conf location and uncomment  <GroupingExtractor> config inside <APIStore> config and add your wrote custom java class name in it.
For eg: <GroupingExtractor>org.wso2.sample.gropuid.impl.RoleBasedGroupingExtractor</GroupingExtractor> 5. Then restart the APIM server. 6. Then try accessing API Store as different users with same ‘Group ID’ value.For example try login to API Store with a developer having ‘manager’ role and do a subscription.Then try to login as another user who also has ‘manager’ role and check his ‘My Applications’ and ‘My subscriptions’ views in API Store. The second user will able to see the first user created application and subscription in his API Store view as below.
Then try to login as an app developer with ‘dev’ role as well.He’ll not able to see the subscriptions/applications of users with ‘manager’ role.
  

  



Thursday, October 29, 2015

Integrate WSO2 registry lifecycle with WSO2 API Manager 1.10



An API artifact has its own lifecycle to govern.A life-cycle contains set of states,actions happened during each state transitions and check list items before do a state transition.With previous APIM previous releases,we had a pre-defined lifecycle with pre-defined six states as ‘CREATED’,’PROTOTYPED’,’PUBLISHED’,’BLOCKED’,’DEPRECATED’,’RETIRED’ and pre-defined actions engaged with each state transitions  which cannot be extend or customize.There was a requirement came from many users,can’t they extend the default API lifecycle engaged with WSO2 API Manager as to add their defined state names,invoke their custom actions during state transitions [eg:send notifications at each transition],add custom checklist items before state transitions.


To achieve above,we decided to integrate WSO2 registry based lifecycle with APIManager.WSO2 registry based lifecycle provides a configurable way to define the lifecycle of an artifact which a user can easily extend.For more information ,refer http://wso2.com/library/tutorials/lifecycles-aspects-wso2-governance-registry/
From APIM 1.10 onwards the default API lifecycle has defined as a xml configuration which a user laterly can extend easily.Following is the default API lifecycle xml configuration shipped with AM 1.10 product and same can be download from here.You can find this from management console by navigating to Extenstions->Configure->Lifecycles left menu.


    
    
        
            

                
                    
                        
                            
                            
                            
                            
                        

                        
                            
                            
                            
                            
                        
                    
                    
                    

                
                
                    
                        
                            
                            
                            
                            
                        
                    
                    
                    
                


                

                    

                        
                            
                            
                            
                            
                            
                            
                            
                            

                        
                    
                    
                    
                    
                    
                    
                

                
                    
                        
                            
                            
                            
                            
                        
                    
                    
                    
                

                
                    
                        
                            
                            
                        
                    
                    
                

                
                
            
        
    

In above configuration,following are the important points.


  1. Lifecycle Name- APILifecycle
  2. Set of states -which are defined as   config elements.In default API lifecycle,it has six states as CREATED,PROTOTYPED,PUBLISHED,BLOCKED,DEPRECATED,RETIRED
  3. A list of checklist items to be satisfied-  
         When the API state is in ‘CREATED’ state and have multiple versions,we are checking two checklist items as ‘Deprecate Old Versions’ and ‘Require Re-subscriptions’.These check list items are defined as    configuration element.
    4.   State transition events -These events are to define from which state to which target state an API can be moved.These are defined as config elements in registry lifecycle. Below state transition chart explain clearly the state transition events in default API lifecycle.


w.png


    5.   Actions for each state transitions
         This is the important part.For each state transition,there has to be an action triggered which will execute during state transition.For example,when an API state change from ‘CREATED’ to ‘PUBLISHED’,from APIM side,there will be an execution happend as a relative synapse API xml element will be created and related API data will be saved in database.To happen that execution,developer has to define the execution for state transtion in above registry lifecycle configuration configuration.


With the above change,lifecycle tab in API Publisher UI has also changed.






On AM 1.10 APIPublisher,the lifecycle UI is showing the current state of an API and target events defined in API lifecycle for that state as buttons.Note this UI is dynamically generated based on defined API LifeCycle xml configuration [Previously this page is static].Thus if you customized the default API LifeCycle configuration included states,transition events or check list items,those changes will be rectified in the lifecycle tab of APIPublisher UI accordingly.


Extension points for the API Lifecycle

With the registry life-cycle integration,now a developer can changed the API lifecycle easily with modify the above mentioned APILifecycle xml configuration.Note he has to keep the lifecycle name as ‘APILifeCycle’ to engage it for an API by default.
He can define his own state names except ‘Published’ and ‘Prototyped’ states as those two two will be use from APIPublisher API creation wizard.He can change state transition events as per their environmental preference by changing APILifecycle accordingly.He can add custom checklist items for specific state transitions.


And also a developer can change the execution code for each state transitions.In default API lifecycle,we have used same execution class  called ‘org.wso2.carbon.apimgt.impl.executors.APIExecutor’
[https://github.com/wso2/carbon-apimgt/blob/release-1.10.x/components/apimgt/org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/executors/APIExecutor.java] for all the state transitions.But a developer can plug their own execution code with modifying the lifecycle configuration.For example,if he want to add notifications for a specific state  transition,then he can plug his own custom execution class for that particular state in APILifeCycle.


Once a developer changed states,events or checklist items,those will be rectified in APIPublisher life-cycle tab.
APIM 1.10 will be release by end quarter of 2015 and you'll able to try out these changes by the that release out.









Tuesday, October 27, 2015

Set custom password policies to APIStore signup


In WSO2 Identity Server, it can define custom password policies and enforce them at user creation. Could the same feature use in  WSO2 APIStore self signup?Yes ,it's possible with following below steps.
To set the user password policy during sign up for Store  in AM 1.9.1,first user need to install the "Account Recovery and Credential Management' feature on top of API Manager 1.9.1. 
1. Log into the APIM's Management Console [https://localhost:9443/carbon]
2. On the left side menu section 'Configure', go to features -> repository Management and add Repository with a relevant name e.g. account-mgt

3. Give the following as the repository URL  and add the repository.


4. Then select  "Show only the latest versions" option in the showing features installation UI and click on "Find the features" button.

5. Then select "Account Recovery and Credential Management 4.2.2" feature and install. 

6. Go through the feature installation process until it completes.
7. Then modify the identity­-mgt.properties  file located in wso2am-1.9.1/repository/conf/security/ according to https://docs.wso2.com/display/IS500/Password+Policies 
8. Restart the server and that's it.Now try self signup feature in APIStore.
For more info on feature installation process,refer[1].
Note- APIStore self signup UI page input password field validation is based on default password policy.You can change it to match with your custom policy by extending the self signup page with your custom html changes via a sub theme.

Monday, October 19, 2015

How to lock a user to avoid token generation via password grant type in APIM 1.7.0

  1. First have to install user lock/unlock feature in APIM 1.7.0.
  2. Login to APIM 1.7.0 management console and navigate to ‘features’ menu via
          left menu ‘Configure -> Features’  and select ‘Add Repository’ from shown UI as below.

          add.png

  1. Then add a new repo with giving the url as http://product-dist.wso2.com/p2/carbon/releases/turing/  and click ‘Add’ button as shown below.
a1.png
   4) Then click on ‘Find Features’ button shown in UI. f.png

   5) There will be a list of features shown based on products. To install user account
       locking/unlocking feature to AM 1.7.0,you have to select the feature Account Recovery and Credential Management -version 4.2.0” from ‘Identity Server 4.5.0 feature group’ under Identity Management features section. Select the feature and click on ‘install’ button as shown below.
i.png

6) Then proceed the feature installation process as shown below.
m.png
l.png
7) Once you successfully installed the above feature,finally you’ll see the below UI.
q.png

8) As mentioned in above UI,you need to restart the server before use the account lock/unlock feature. But before restart the server, change the below configuration entries in identity-mgt.properties file located at AM/repository/conf/security to enable locking feature.

Identity.Listener.Enable=true
Authentication.Policy.Enable=true

For more information on configurations on account locking,please refer https://docs.wso2.com/pages/viewpage.action?pageId=30541686

Once you did the above config changes for locking feature,restart the server.

9) Once restarted the server,now create a new user and assign a suitable role.Then lock the user.
You can try locking the user via admin service[https://localhost:9443/services/UserIdentityManagementAdminService?wsdl] or via carbon UI.

Below steps are on how to lock a user from carbon UI.

--Go to management console  and navigate to Configure->claim management UI.Then set ‘accountLocked’ claim as  ‘ supported by default’ true by following below UI flow.
w.png
e.png

r.png

  -- Then click on ‘Configure->Users and Roles’ left menu and navigate to users list.Click on ‘User Profile’ link of newly created user.
u.png

-- Then set the  ‘accountLocked’ value as ‘true’ and update the user profile.
p.png
Now the user is locked.

10) Now try to generate the token with giving newly created user’s credentials via password grant type as follows.

curl -k -d "grant_type=password&username=lalaji2&password=xxxx&scope=PRODUCTION" -H "Authorization: Basic RFY0dtNDFJVk50VUl2YXdMeDJubUxFYTozNG9aTmZhQmpHWHdUQmo1N19mT045dHpqaUVh, Content-Type: application/x-www-form-urlencoded" https://localhost:8243/token

You’ll see the below response coming from APIM to client app.
{"error":"invalid_grant","error_description":"Provided Authorization Grant is invalid."}

And  following warning and the error will shown in the APIM logs.

[2015-10-19 10:55:36,586]  WARN - IdentityMgtEventListener User account is locked for user : lalaji2. cannot login until the account is unlocked
[2015-10-19 10:55:36,586] ERROR - PasswordGrantHandler Error when authenticating the user for OAuth Authorization.
org.wso2.carbon.user.core.UserStoreException: 17003
at org.wso2.carbon.identity.mgt.IdentityMgtEventListener.doPreAuthenticate(IdentityMgtEventListener.java:167)
xxxxxx