Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Thursday, November 20, 2014

User Self Registration & Account Confirmation with WSO2 Identity Server 5.0.0

If you have any enterprise application, registration of users and confirming there account and emails is a primary task. If your platform's identity server is WSO2 Identity Server, those tasks are built in and very easy to manage. In this article I am going to explain how we can enable User Self Registration & Account Confirmation using WSO2 Identity Server 5.0.0.

As usual the necessary API methods are exposed as a admin level SOAP API in WSO2 Identity Server. First of all you need to enable admin service visible to outside using carbon.xml. Then go to https://idnetity-server-host:idnetity-server-port/services/UserInformationRecoveryService?wsdl. (Default  idnetity-server-port = 9443) Then you can see the WSDL for the UserInformationRecoveryService which expose the API method to do User Self Registration & Account Confirmation. The important methods for our task are,
  • getUserIdentitySupportedClaims() - This method returns the claims URIs needed to register a user in WSO2 Identity Server
  • registerUser() - This method will register a user in WSO2 Identity Server
  • getCaptcha() - This methods help to generate captcha to verify the user is human
  • confirmUserSelfRegistration() - This method will confirm the user registration
Then I need to explain how to configure WSO2 Identity Server to do this process and steps of the process.  The key point of the process are,
  • First of all you need to know what are the data AKA claims needs to register a user in  WSO2 Identity Server. You can get those details by simple calling getUserIdentitySupportedClaims() method of the  UserInformationRecoveryService. The SOAP Request will look like,
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://services.mgt.identity.carbon.wso2.org">
       <soapenv:Header/>
       <soapenv:Body>
          <ser:getUserIdentitySupportedClaims>
             <ser:dialect>http://wso2.org/claims</ser:dialect>
          </ser:getUserIdentitySupportedClaims>
       </soapenv:Body>
    </soapenv:Envelope> 
Actually if you are aware of the claims you need not to call this method.
  • Then you need to call the registerUser method. The SOAP request will look like this,
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ser="http://services.mgt.identity.carbon.wso2.org" xmlns:xsd="http://dto.mgt.identity.carbon.wso2.org/xsd"> <soap:Header/> <soap:Body> <ser:registerUser> <ser:userName>user</ser:userName> <ser:password>password</ser:password> <ser:claims> <xsd:claimUri>http://wso2.org/claims/emailaddress</xsd:claimUri> <xsd:claimValue>email</xsd:claimValue> </ser:claims> <ser:claims> <xsd:claimUri>http://wso2.org/claims/givenname</xsd:claimUri> <xsd:claimValue>firstname</xsd:claimValue> </ser:claims> <ser:claims> <xsd:claimUri>http://wso2.org/claims/lastname</xsd:claimUri> <xsd:claimValue>familyname</xsd:claimValue> </ser:claims> <ser:claims> <xsd:claimUri>http://wso2.org/claims/organization</xsd:claimUri> <xsd:claimValue>organization</xsd:claimValue> </ser:claims> <ser:tenantDomain></ser:tenantDomain> </ser:registerUser> </soap:Body> </soap:Envelope>
  • As soon as the user is registered they will be not allowed to login. They need to confirm there email accounts. To do that we need to configure IS like this. Open the WSO2_Identity_Server_Folder/repository/conf/security/identity­-mgt.properties. In that add this entry,
Authentication.Policy.Account.Lock.On.Creation=true
This will guarantee that user cant login as soon as they register. They need to verify there email.
  • As soon as user register, we need to send an email to user to confirm there account. That can be done with in the IS. To do that open the identity­-mgt.properties file again and add these entries.'
Identity.Listener.Enable=true
Notification.Sending.Internally.Managed=true
Notification.Expire.Time=7200
Notification.Sending.Enable=true
Authentication.Policy.Enable=true 
  • To send emails, you need to enable mailto transport in  WSO2 Identity Server. To do that open WSO2_Identity_Server_Folder/repository/conf/axis2/axis2.xml file. In that un-comment following entries and change to suitable SMTP configurations. 
<transportSender name="mailto" class="org.apache.axis2.transport.mail.MailTransportSender"> <parameter name="mail.smtp.host">smtp.gmail.com</parameter> <parameter name="mail.smtp.port">587</parameter> <parameter name="mail.smtp.starttls.enable">true</parameter> <parameter name="mail.smtp.auth">true</parameter> <parameter name="mail.smtp.user">synapse.demo.0</parameter> <parameter name="mail.smtp.password">mailpassword</parameter> <parameter name="mail.smtp.from">synapse.demo.0@gmail.com</parameter> </transportSender>
  • The account if confirmed when the confirmUserSelfRegistration() method is called. So in the account confirmation email we need to send a link to invoke that method. In my example I am sending a link to a Java servlet which we will call this method.
  • To send account registration email, we need to create a template. We can do that by editing  WSO2_Identity_Server_Folder/repository/conf/email/email­-admin­-config.xml. Edit the accountConfirmation entry. It will look like this,
<configuration type="accountConfirmation"> <targetEpr></targetEpr> <subject>XYZ Registration - Confirm Account Registration</subject> <body> Hi {first-name}, You have created an account in XYZ with following user name User Name: {user-name} Please click the following link to complete the registration. If clicking the link doesn't seem to work, you can copy and paste the link into your browser's address window. https://xyz.com/confirmRegistration?confirmationCode={confirmation-code}&amp;userName={user-name} </body> <footer> Best Regards, XYZ Inc. www.xyz.com </footer> <redirectPath></redirectPath> </configuration>
The given link will call the servlet which I have mentioned above.
  • Before confirm the registration we can check whether this call is made by a human. To do that we can use a captcha. The captcha based validation process is like this,
- Get captcha image from IS
- Captcha will be returned with a image and a secret key for image
- Send the users input for captcha along with secret key while we call confirmation method
To get a captcha we can call getCaptcha method of above service. The SOAP request will look like this,
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://services.mgt.identity.carbon.wso2.org">
    <soapenv:Header/>
    <soapenv:Body>
        <ser:getCaptcha/>
    </soapenv:Body>
</soapenv:Envelope> 
  • If we don't need captcha based validation we can configure it. To do that edit the following entry in WSO2_Identity_Server_Folder/repository/conf/security/identity­-mgt.properties file.
Captcha.Verification.Internally.Managed=true
  • Then you need to call the confirmUserSelfRegistration method to complete the registration. The SOAP request looks like this,
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://services.mgt.identity.carbon.wso2.org" xmlns:xsd="http://beans.mgt.captcha.carbon.wso2.org/xsd"> <soapenv:Header/> <soapenv:Body> <ser:confirmUserSelfRegistration> <ser:username>xyz</ser:username> <ser:code>xyz</ser:code> <ser:captcha> <xsd:imagePath>xyz</xsd:imagePath> <xsd:secretKey>xyz</xsd:secretKey> <xsd:userAnswer>xyz</xsd:userAnswer> </ser:captcha> <ser:tenantDomain></ser:tenantDomain> </ser:confirmUserSelfRegistration> </soapenv:Body> </soapenv:Envelope>
If we are not using captcha validation we don't need to send those parameters.
  • After a successful call the above method will complete the registration. Then user will be able to login. The account will be unlocked.
  • All the above methods should be called wiht Basic Auth Header with admin user name and password.
Lets look at how to do this with JAVA. To call the SOAP service we can use the STUB provided in side the product. That is org.wso2.carbon.identity.mgt.stub. Using that we can call the UserInformationRecoveryService easily. Thisis how you can call user registration service,

import org.apache.axis2.AxisFault;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.transport.http.HttpTransportProperties;
import org.emojot.webUI.Config;
import org.wso2.carbon.identity.mgt.stub.UserInformationRecoveryServiceIdentityMgtServiceExceptionException;
import org.wso2.carbon.identity.mgt.stub.UserInformationRecoveryServiceStub;
import org.wso2.carbon.identity.mgt.stub.beans.VerificationBean;
import org.wso2.carbon.identity.mgt.stub.dto.UserIdentityClaimDTO;
import java.rmi.RemoteException;
import java.util.Map;
import java.util.Properties;

public class UserRegistration  {

    public static void main(String[] args) {

        UserInformationRecoveryServiceStub stub=null;
        HttpTransportProperties.Authenticator authenticator = null;
        Map properties=null;

        String serviceURL = Config.isURL + "/services/UserInformationRecoveryService";

        try {
            stub = new UserInformationRecoveryServiceStub(null, serviceURL);
            ServiceClient client = stub._getServiceClient();
            Options options = client.getOptions();

            authenticator = new HttpTransportProperties.Authenticator();
            authenticator.setUsername(Config.isAdminUserName);
            authenticator.setPassword(Config.isAdminPassword);

            properties = new Properties();
            properties.put(org.apache.axis2.transport.http.HTTPConstants.AUTHENTICATE, authenticator);

            options.setProperties(properties);

        } catch (AxisFault axisFault) {
            System.out.println(axisFault.getMessage());
            System.out.println(axisFault.getDetail().toString());
        }

        String userName="username1";
        String password="password1";
        String emailaddress="username1@XYZ.com";
        String givenname="username1";
        String lastname="username1";
        String organization="XYZ";

            if(stub!=null){
                try {
                    UserIdentityClaimDTO claimEmailaddress=new UserIdentityClaimDTO();
                    claimEmailaddress.setClaimUri(UserMgtConstants.claimEmailaddress);
                    claimEmailaddress.setClaimValue(emailaddress);

                    UserIdentityClaimDTO claimGivenname=new UserIdentityClaimDTO();
                    claimGivenname.setClaimUri(UserMgtConstants.claimGivenname);
                    claimGivenname.setClaimValue(givenname);

                    UserIdentityClaimDTO claimLastname=new UserIdentityClaimDTO();
                    claimLastname.setClaimUri(UserMgtConstants.claimLastname);
                    claimLastname.setClaimValue(lastname);

                    UserIdentityClaimDTO claimOrganization=new UserIdentityClaimDTO();
                    claimOrganization.setClaimUri(UserMgtConstants.claimOrganization);
                    claimOrganization.setClaimValue(organization);

                    UserIdentityClaimDTO claims[]=new UserIdentityClaimDTO[]{claimEmailaddress,claimGivenname,claimLastname,claimOrganization};

                    VerificationBean verificationBean= stub.registerUser(userName, password, claims, null, null);
                    System.out.println("Successfully Registered the User -"+verificationBean.getUserId()+" Verification Key -"+verificationBean.getKey());

                } catch (UserInformationRecoveryServiceIdentityMgtServiceExceptionException e) {
                    System.out.println(e.getMessage());
                    System.out.println(e.getFaultMessage());
                } catch (RemoteException e) {
                    System.out.println(e.getMessage());
                }
            }else{
                System.out.println("Internal Error - Stub Creation Failed");
            }       
    }
}


After that you need to call the confirmation method. That can be also done like this. Here I am not using the internal captcha validation.

import org.apache.axis2.AxisFault;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.transport.http.HttpTransportProperties;
import org.emojot.webUI.Config;
import org.wso2.carbon.identity.mgt.stub.UserInformationRecoveryServiceIdentityMgtServiceExceptionException;
import org.wso2.carbon.identity.mgt.stub.UserInformationRecoveryServiceStub;
import org.wso2.carbon.identity.mgt.stub.beans.VerificationBean;
import org.wso2.carbon.identity.mgt.stub.dto.UserIdentityClaimDTO;
import java.rmi.RemoteException;
import java.util.Map;
import java.util.Properties;

public class RegistrationConfirm {

     public static void main(String[] args) {

        UserInformationRecoveryServiceStub stub=null;
        HttpTransportProperties.Authenticator authenticator = null;
        Map properties=null;

        String serviceURL = Config.isURL + "/services/UserInformationRecoveryService";
        try {

            stub = new UserInformationRecoveryServiceStub(null, serviceURL);
            ServiceClient client = stub._getServiceClient();
            Options options = client.getOptions();

            authenticator = new HttpTransportProperties.Authenticator();
            authenticator.setUsername(Config.isAdminUserName);
            authenticator.setPassword(Config.isAdminPassword);

            properties = new Properties();
            properties.put(org.apache.axis2.transport.http.HTTPConstants.AUTHENTICATE, authenticator);

            options.setProperties(properties);
        } catch (AxisFault axisFault) {
            System.out.println(axisFault.getMessage());
            System.out.println(axisFault.getDetail().toString());
        }

        String userName="username1";
        String confirmationCode="13677e9d-e3c8-4a78-a6e0-569163e66fba";

            if(stub!=null){
                try {
                    VerificationBean verificationBean= stub.confirmUserSelfRegistration(userName, confirmationCode, null,null);
                    System.out.println("Successfully Registered the User-" + userName + " Registration Confirmed -" + verificationBean.getVerified());
                } catch (UserInformationRecoveryServiceIdentityMgtServiceExceptionException e) {
                    System.out.println(e.getMessage());
                    System.out.println(e.getFaultMessage());
                } catch (RemoteException e) {
                    System.out.println(e.getMessage());
                }
            }else{
                System.out.println("Internal Error - Stub Creation Failed");
            }
    }
}

Hoep this post helps you. If you have any query please contact me.

    Sunday, June 1, 2014

    WSO2 CEP Custom Output Event Adapter for MongoDB

    WSO2 CEP uses output adapters to send event from the CEP. We can write our own adapters to support our own output formats. That process is described in https://docs.wso2.org/display/CEP310/Writing+Custom+Event+Adaptors.

    I am going to share my own implementation of a Output Event Adapter which uses to store event in a MongoDB database. The code is,

    package org.emojot.cep.output.adaptor.mongodb;
    
    import com.mongodb.*;
    import com.mongodb.util.JSON;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.emojot.cep.output.adaptor.mongodb.internal.util.EmojotMongoDBEventAdaptorConstants;
    import org.json.JSONException;
    import org.json.JSONObject;
    import org.wso2.carbon.event.output.adaptor.core.AbstractOutputEventAdaptor;
    import org.wso2.carbon.event.output.adaptor.core.MessageType;
    import org.wso2.carbon.event.output.adaptor.core.Property;
    import org.wso2.carbon.event.output.adaptor.core.config.OutputEventAdaptorConfiguration;
    import org.wso2.carbon.event.output.adaptor.core.message.config.OutputEventAdaptorMessageConfiguration;
    
    import java.net.UnknownHostException;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Locale;
    import java.util.ResourceBundle;
    
    public final class EmojotMongoDBEventAdaptorType extends AbstractOutputEventAdaptor {
    
    
        private static final Log log = LogFactory.getLog(EmojotMongoDBEventAdaptorType.class);
        private ResourceBundle resourceBundle;
        private List<Property> adaptorPropertyList;
        private List<Property> outputMessagePropertyList;
        private List<String> messageTypes;
    
    
        @Override
        protected String getName() {
            return EmojotMongoDBEventAdaptorConstants.EVENT_ADAPTOR_TYPE_EmojotMongoDB;
        }
    
        @Override
        protected List<String> getSupportedOutputMessageTypes() {
            return messageTypes;
        }
    
        @Override
        protected void init() {
            this.resourceBundle = ResourceBundle.getBundle("org.emojot.cep.output.adaptor.mongodb.i18n.Resources", Locale.getDefault());
    
            adaptorPropertyList = new ArrayList<Property>();
            outputMessagePropertyList = new ArrayList<Property>();
            messageTypes = new ArrayList<String>();
    
    
            Property property1 = new Property(EmojotMongoDBEventAdaptorConstants.EVENT_ADAPTOR_CONF_FIELD1);
            property1.setDisplayName(
                    resourceBundle.getString(EmojotMongoDBEventAdaptorConstants.EVENT_ADAPTOR_CONF_FIELD1));
            property1.setRequired(true);
            property1.setHint(resourceBundle.getString(EmojotMongoDBEventAdaptorConstants.EVENT_ADAPTOR_CONF_FIELD1_HINT));
            this.adaptorPropertyList.add(property1);
    
            Property property2 = new Property(EmojotMongoDBEventAdaptorConstants.EVENT_ADAPTOR_CONF_FIELD2);
            property2.setDisplayName(
                    resourceBundle.getString(EmojotMongoDBEventAdaptorConstants.EVENT_ADAPTOR_CONF_FIELD2));
            property2.setRequired(true);
            property2.setHint(resourceBundle.getString(EmojotMongoDBEventAdaptorConstants.EVENT_ADAPTOR_CONF_FIELD2_HINT));
            this.adaptorPropertyList.add(property2);
    
            Property property3 = new Property(EmojotMongoDBEventAdaptorConstants.EVENT_ADAPTOR_CONF_FIELD3);
            property3.setDisplayName(
                    resourceBundle.getString(EmojotMongoDBEventAdaptorConstants.EVENT_ADAPTOR_CONF_FIELD3));
            property3.setRequired(true);
            property3.setHint(resourceBundle.getString(EmojotMongoDBEventAdaptorConstants.EVENT_ADAPTOR_CONF_FIELD3_HINT));
            this.adaptorPropertyList.add(property3);
    
    
            Property message_property1 = new Property(EmojotMongoDBEventAdaptorConstants.EVENT_ADAPTOR_Message_CONF_FIELD1);
            message_property1.setDisplayName(
                    resourceBundle.getString(EmojotMongoDBEventAdaptorConstants.EVENT_ADAPTOR_Message_CONF_FIELD1));
            message_property1.setRequired(true);
            message_property1.setHint(resourceBundle.getString(EmojotMongoDBEventAdaptorConstants.EVENT_ADAPTOR_Message_CONF_FIELD1_HINT));
            this.outputMessagePropertyList.add(message_property1);
    
            this.messageTypes.add(MessageType.JSON);
    
        }
    
        @Override
        protected List<Property> getOutputAdaptorProperties() {
            return  this.adaptorPropertyList;
        }
    
        @Override
        protected List<Property> getOutputMessageProperties() {
            return  this.outputMessagePropertyList;
        }
    
        @Override
        public void publish(
                OutputEventAdaptorMessageConfiguration outputEventAdaptorMessageConfiguration,
                Object o, OutputEventAdaptorConfiguration outputEventAdaptorConfiguration,
                int tenantId) {
    
    
            String mongodbIPAddress=outputEventAdaptorConfiguration.getOutputProperties().get(EmojotMongoDBEventAdaptorConstants.EVENT_ADAPTOR_CONF_FIELD1);
            String mongodbPort=outputEventAdaptorConfiguration.getOutputProperties().get(EmojotMongoDBEventAdaptorConstants.EVENT_ADAPTOR_CONF_FIELD2);
            String mongodbDatabase=outputEventAdaptorConfiguration.getOutputProperties().get(EmojotMongoDBEventAdaptorConstants.EVENT_ADAPTOR_CONF_FIELD3);
    
            String mongodbCollection=outputEventAdaptorMessageConfiguration.getOutputMessageProperties().get(EmojotMongoDBEventAdaptorConstants.EVENT_ADAPTOR_Message_CONF_FIELD1);
    
            log.info("Configurations -"+mongodbIPAddress+":"+mongodbPort+":"+mongodbDatabase+":"+mongodbCollection);
            log.info("Output -"+o.toString());
            log.info("Output Type-"+o.getClass().getName());
    
            try {
                MongoClient mongoClient = new MongoClient( mongodbIPAddress, Integer.parseInt(mongodbPort) );
                DB db = mongoClient.getDB( mongodbDatabase );
                DBCollection collection = db.getCollection(mongodbCollection);
    
                if("java.lang.String".equals(o.getClass().getName())) {
                    JSONObject result= new JSONObject(o.toString());
                    JSONObject payload=result.getJSONObject("event").getJSONObject("payloadData");
    
                    log.info("Output JSON-"+payload.toString());
    
                    DBObject dbObject = (DBObject)JSON.parse(payload.toString());
                    collection.insert(dbObject);
                }
                else{
                    log.error("Output Event is not in Correct Type");
                }
    
            } catch (UnknownHostException e) {
                log.error("Error Opening Connection to Mongodb Database" + e.toString());
            } catch (JSONException e) {
                log.error("Error Parsing JSON Result" + e.toString());
            }
        }
    
        @Override
        public void testConnection(
                OutputEventAdaptorConfiguration outputEventAdaptorConfiguration, int tenantId) {
            //To change body of implemented methods use File | Settings | File Templates.
        }
    }

    JAVA client to SAML2 Bearer Assertion Profile for OAuth 2.0

    In SAML2 Bearer Assertion Profile for OAuth 2.0 user can get a SAML token from WSO2 Identity Server by authenticating. After that user can give that SAML token to WSO2 API Manger to get an OAuth token without going for authentication.I am giving you a JAVA client to exchange SAML token to OAuth token.

    import org.example.webUI.Config;
    import org.opensaml.Configuration;
    import org.opensaml.DefaultBootstrap;
    import org.opensaml.saml2.core.Response;
    import org.opensaml.xml.ConfigurationException;
    import org.opensaml.xml.XMLObject;
    import org.opensaml.xml.io.Unmarshaller;
    import org.opensaml.xml.io.UnmarshallerFactory;
    import org.opensaml.xml.io.UnmarshallingException;
    import org.opensaml.xml.util.Base64;
    import org.opensaml.xml.util.XMLHelper;
    import org.w3c.dom.Document;
    import org.w3c.dom.Element;
    import org.xml.sax.SAXException;
    
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    import javax.xml.parsers.ParserConfigurationException;
    import java.io.*;
    import java.net.HttpURLConnection;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.net.URLEncoder;
    import java.util.HashMap;
    
    public class OAuthUtil {
    
        public static String exchangeSAMLTokenToOauth(String responseMessage) throws ConfigurationException, ParserConfigurationException, IOException, SAXException, UnmarshallingException {
    
            DefaultBootstrap.bootstrap();
    
            byte[] decoded = Base64.decode(responseMessage);
    
            ByteArrayInputStream is = new ByteArrayInputStream(decoded);
    
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            documentBuilderFactory.setNamespaceAware(true);
            DocumentBuilder docBuilder = documentBuilderFactory.newDocumentBuilder();
    
            Document document = docBuilder.parse(is);
            Element element = document.getDocumentElement();
    
            UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory();
            Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(element);
            XMLObject responseXmlObj = unmarshaller.unmarshall(element);
    
            Response responseObj = (Response) responseXmlObj;
    
    
            // Get the SAML2 Assertion part from the response
            StringWriter rspWrt = new StringWriter();
            XMLHelper.writeNode(responseObj.getAssertions().get(0).getDOM(), rspWrt);
            String requestMessage = rspWrt.toString();
    
            // Get the Base64 encoded string of the message
            // Then Get it prepared to send it over HTTP protocol
            String encodedRequestMessage = Base64.encodeBytes(requestMessage.getBytes(), Base64.DONT_BREAK_LINES);
            String enc_rslt = URLEncoder.encode(encodedRequestMessage, "UTF-8").trim();
    
            //Create connection to the Token endpoint of API manger
            URL url = new URL(Config.apiMangerOAuthURL);
    
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
    
            String userCredentials = Config.apiMangerClientID+":"+Config.apiMangerClientSecret;
            String basicAuth = "Basic " + new String(Base64.encodeBytes(userCredentials.getBytes()));
            basicAuth = basicAuth.replaceAll("\\r|\\n", "");
    
            // Set the consumer-key and Consumer-secret
            connection.setRequestProperty("Authorization", basicAuth);
            connection.setUseCaches(false);
            connection.setDoInput(true);
            connection.setDoOutput(true);
    
            //Send request
            DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
            wr.writeBytes("grant_type=urn:ietf:params:oauth:grant-type:saml2-bearer&assertion=" + enc_rslt + "&scope=PRODUCTION");
            wr.flush();
            wr.close();
    
            //Get Response
            InputStream iss = connection.getInputStream();
            BufferedReader rd = new BufferedReader(new InputStreamReader(iss));
    
            String line;
            StringBuffer responseString = new StringBuffer();
            while ((line = rd.readLine()) != null) {
                responseString.append(line);
                responseString.append('\r');
            }
    
            rd.close();
            return responseString.toString();
        }
    
        public static boolean revokeToken(Token token) throws IOException {
            //Create connection to the Token endpoint of API manger
            URL url = new URL(Config.apiMangerOAuthRevokeURL);
    
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
    
            String userCredentials = Config.apiMangerClientID+":"+Config.apiMangerClientSecret;
            String basicAuth = "Basic " + new String(Base64.encodeBytes(userCredentials.getBytes()));
            basicAuth = basicAuth.replaceAll("\\r|\\n", "");
    
            // Set the consumer-key and Consumer-secret
            connection.setRequestProperty("Authorization", basicAuth);
            connection.setUseCaches(false);
            connection.setDoInput(true);
            connection.setDoOutput(true);
    
            //Send request
            DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
            wr.writeBytes("token="+token.getAccess_token());
            wr.flush();
            wr.close();
    
            //Get Response
            InputStream iss = connection.getInputStream();
            BufferedReader rd = new BufferedReader(new InputStreamReader(iss));
    
            String line;
            StringBuffer responseString = new StringBuffer();
            while ((line = rd.readLine()) != null) {
                responseString.append(line);
                responseString.append('\r');
            }
    
            rd.close();
    
            System.out.println("Revoking Token -"+token.getAccess_token());
            System.out.println("Revoking Response -"+responseString.toString());
    
            return true
                    ;
        }
    }

    The related token class is this,

    public class Token {
        private String access_token,refresh_token,expires_in,token_type;
    
        public Token(String access_token, String refresh_token, String expires_in, String token_type) {
            this.access_token = access_token;
            this.refresh_token = refresh_token;
            this.expires_in = expires_in;
            this.token_type = token_type;
        }
    
        public String getRefresh_token() {
            return refresh_token;
        }
    
        public void setRefresh_token(String refresh_token) {
            this.refresh_token = refresh_token;
        }
    
        public String getAccess_token() {
            return access_token;
        }
    
        public void setAccess_token(String access_token) {
            this.access_token = access_token;
        }
    
        public String getExpires_in() {
            return expires_in;
        }
    
        public void setExpires_in(String expires_in) {
            this.expires_in = expires_in;
        }
    
        public String getToken_type() {
            return token_type;
        }
    
        public void setToken_type(String token_type) {
            this.token_type = token_type;
        }
    }
    
    Hope this helped you! 

    Monday, July 15, 2013

    Communicating with WSO2 CEP through Thrift in NodeJS + JAVA

    In our  final year research project we use WSO2 CEP to analyze complex event coming through a JSON stream. That JSON stream is coming form a NodeJS application. In this article I am describing how to send the JSON stream to WSO2 CEP using Thrift.

    Initially I have developed a JAVA Thrift client to send JSON events to WSO2 CEP. That can be found in here https://github.com/andunslg/Sith/tree/master/SithCEPPublisher.

    SithCEPPublisher is the main communicator class,
    package org.sith.cep.publisher;
    
    import org.sith.cep.publisher.config.SithPerceptionPublisherStreamConfig;
    import org.sith.cep.publisher.config.StreamConfig;
    import org.wso2.carbon.databridge.agent.thrift.DataPublisher;
    import org.wso2.carbon.databridge.agent.thrift.exception.AgentException;
    import org.wso2.carbon.databridge.commons.exception.*;
    import java.net.MalformedURLException;
    
    public class SithCEPPublisher{
    
        private DataPublisher dataPublisher;
        private StreamConfig streamConfig;
    
        public SithCEPPublisher(String url, String userName, String password){
    
            //KeyStoreUtil.setTrustStoreParams();
            System.setProperty("javax.net.ssl.trustStore","wso2carbon.jks");
            System.setProperty("javax.net.ssl.trustStorePassword", "wso2carbon");
    
            System.out.println("Key Store is set..");
            //according to the convention the authentication port will be 7611+100= 7711 and its host will be the same
    
            try{
                dataPublisher = new DataPublisher(url, userName, password);
            }catch(MalformedURLException e){
                e.printStackTrace();
            }catch(AgentException e){
                e.printStackTrace();
            }catch(AuthenticationException e){
                e.printStackTrace();
            }catch(TransportException e){
                e.printStackTrace();
            }
    
            System.out.println("Logged in..");        
            this.streamConfig=new SithPerceptionPublisherStreamConfig();
            System.out.println("Default Stream Config Added..");
        }
    
        public SithCEPPublisher(String url, String userName, String password,String streamName, String streamVersion, String streamDefinition){
    
            //KeyStoreUtil.setTrustStoreParams();
            System.setProperty("javax.net.ssl.trustStore","wso2carbon.jks");
            System.setProperty("javax.net.ssl.trustStorePassword", "wso2carbon");
    
            System.out.println("Key Store is set..");
            //according to the convention the authentication port will be 7611+100= 7711 and its host will be the same
    
            try{
                dataPublisher = new DataPublisher(url, userName, password);
            }catch(MalformedURLException e){
                e.printStackTrace();
            }catch(AgentException e){
                e.printStackTrace();
            }catch(AuthenticationException e){
                e.printStackTrace();
            }catch(TransportException e){
                e.printStackTrace();
            }
    
            System.out.println("Logged in..");
    
            this.streamConfig=new StreamConfig(streamName,streamVersion,streamDefinition);
            System.out.println("Stream Config Added..");
        }
    
        public String publishToCEP(Object[] metaDataArray,Object[] payloadArray) {
    
            System.out.println("Starting publishing process..");
            String streamId;
    
            try {
                streamId = dataPublisher.findStream(streamConfig.getStreamName(), streamConfig.getStreamVersion());
            } catch (NoStreamDefinitionExistException e) {
                try{
                    streamId = dataPublisher.defineStream(streamConfig.getStreamDefinition());
                    System.out.println("Stream Definition created..");
                }catch(AgentException e1){
                    e1.printStackTrace();
                    return "Failed";
                }catch(MalformedStreamDefinitionException e1){
                    e1.printStackTrace();
                    return "Failed";
                }catch(StreamDefinitionException e1){
                    e1.printStackTrace();
                    return "Failed";
                }catch(DifferentStreamDefinitionAlreadyDefinedException e1){
                    e1.printStackTrace();
                    return "Failed";
                }
    
            }catch(StreamDefinitionException e){
                e.printStackTrace();
                return "Failed";
            }catch(AgentException e){
                e.printStackTrace();
                return "Failed";
            }
    
            System.out.println("Stream created..");
    
            try{
                //dataPublisher.publish(streamId, new Object[]{ipAddress}, null, new Object[]{eventID, userID, percetionValue});
                dataPublisher.publish(streamId, metaDataArray, null, payloadArray);
            }catch(AgentException e){
                e.printStackTrace();
                return "Failed";
            }
            System.out.println("Data published..");
            return "Done";
        }
    }
    The I have two configuration classes,

    StreamConfig class which has the configuration of JSON stream,
    package org.sith.cep.publisher.config;
    
    public class StreamConfig{
    
        private String streamName;
        private String streamVersion;
        private String streamDefinition;
    
        public StreamConfig(String streamName, String streamVersion, String streamDefinition){
            this.streamName=streamName;
            this.streamVersion=streamVersion;
            this.streamDefinition=streamDefinition;
        }
    
        public String getStreamName(){
            return streamName;
        }
    
        public void setStreamName(String streamName){
            this.streamName=streamName;
        }
    
        public String getStreamVersion(){
            return streamVersion;
        }
    
        public void setStreamVersion(String streamVersion){
            this.streamVersion=streamVersion;
        }
    
        public String getStreamDefinition(){
            return streamDefinition;
        }
    
        public void setStreamDefinition(String streamDefinition){
            this.streamDefinition=streamDefinition;
        }
    }
    
    

    SithPerceptionPublisherStreamConfig class which holds the stream definition,

    package org.sith.cep.publisher.config;
    
    public class SithPerceptionPublisherStreamConfig extends StreamConfig{
        private static String sithPerceptionStreamName="sith_Perception_Analytic";
        private static String sithPerceptionStreamVersion="1.0.0";
        private static String sithPerceptionStreamDefinition=
    
                        "{"+
                        "    'name':'sith_Perception_Analytics',"+
                        "    'version':'1.0.0',"+
                        "    'nickName': 'Sith Analytics',"+
                        "    'description': 'Sith_Perception_Analytics',"+
                        "    'metaData':["+
                        "        {"+
                        "            'name':'ipAdd','type':'STRING'\n"+
                        "        }"+
                        "    ],"+
                        "    'payloadData':["+
                        "        {"+
                        "            'name':'eventID','type':'STRING'"+
                        "        },"+
                        "        {"+
                        "            'name':'userID','type':'STRING'"+
                        "        },"+
                        "        {"+
                        "            'name':'perceptionValue','type':'STRING'"+
                        "        },"+
                        "        {"+
                        "            'name':'comment','type':'STRING'"+
                        "        }"+
                        "    ]"+
                        "}";
    
        public SithPerceptionPublisherStreamConfig(){
            super(sithPerceptionStreamName,sithPerceptionStreamVersion,sithPerceptionStreamDefinition);
        }
    
    }
    
    
    Then what I have did was invoking this JAVA code using nodejs application. To do that I have used this nodejs module which provides cross language integration. https://github.com/nearinfinity/node-java. The node JS appication is given below,
    exports.publishComment = function(req,res){
        percepManager.publishToCEP(req.body.userID , req.body.eventID , req.body.perceptionValue,req.body.text);
        res.writeHead(200, {'Content-Type': 'application/json'});
          var result = JSON.stringify({response: true });
        res.write(result);
        res.end();
    }
    
    var java = require("java");
    java.classpath.push("cep-publisher-1.0.jar");
    var jClass = java.newInstanceSync("org.sith.cep.publisher.SithCEPPublisher","tcp://192.248.8.246:7611","admin","apst@sith");
    
    exports.publishToCEP = function(userID,eventID,perceptionVal,comment) {
        var metaDataArray = java.newArray("java.lang.Object", ["192.248.8.246"]);
        var payloadArray = java.newArray("java.lang.Object", [eventID,userID,perceptionVal,comment]);
        var result=jClass.publishToCEPSync(metaDataArray,payloadArray);
        console.log("Returned data - "+result);
    } 
    To run this application what you have to do is run npm install java and then run node app command. After that you can call this method to send the defined JSON stream to CEP.

    Wednesday, April 17, 2013

    How to show a Jasper report in your web page in PDF format

    Jasper is a powerful tool which can be used to generate reports for several data sources. These data sources can be MySQL database, Oracle databases etc. In this article, I will show you how to give report on a MySQL database using Jasper as a PDF in your web site.

    Pre - Requisites,

    Following software and tools have to be in your pc,
    Optional,
    Say if you have a MySQL database which has the marks of a particular subject for a set of students.


    If you want to give report about students marks as a chart, you can use Jasper for the task. I will show you how to give the student's marks graph as PDF in your web site using Jasper.

    First task will be creating a Jasper report File(.jrxml) using iReport designer to generate the student marks chart.

    Step 1 - Open iReport Designer and Click File - > New. Then select Report template and click the button Open this template.


    Step 2 - Give a name to the report project and click next



    Step 3 - The new report will be shown in the iReport designer. Click on the Report Datasources button and then click new button.




    Step 4 - Click on the Database JDBC Connection an click next.




    Step 5 - Select MySQL as JDBC driver type and enter the details for your database connection. Then click save button to go back to the report.



    Step 6 - Click on the Report Query Button on the report and following UI will be shown. In that type the SQL query which you need to add to your report. I have used "select * from Marks".




    Step 7 - When we typed the query, all the field will be retrieved automatically. Click the preview data button to view the data. Then click OK.




    Step 8 - Drag and drop a Static TextBox from palette to the report and give title to the report. I have used "Student Marks".

    Step 9 - Drag and drop a Chart from palette to the report's summary section . It will show following UI. In that select line chart.


    Step 10 - In the next dialog click the edit button near the text Dummy Series to edit the name of the data series of the graph. I have used Student Marks as the data series name. An click apply and next.






    Step 11 - In the next dialog click the edit button in the category expression to select the value set for the X axis of the chart.


    Step 12 - In the next dialog, I have double clicked on the column name to add it as the data series for the X axis.



    Step 13 - In the next dialog click the edit button in the value expression to select the value set for the Y axis of the chart. In the next dialog, I have double clicked on the column marks to add it as the data series for the Y axis. And  then click Finish.



    Step 14 - Now you have completed your Jasper report. Click on the XML tab to view the jrxml file for the particular report and Preview tab to view the report.





    Step 15 - Save your jrxml file in a known location. It will be needed to future steps.

    Next step will be adding this report to a web page as PDF which user can view or download. For that I a going to create a web application using intelliJ IDEA. Please follow this tutorial to see how to create a web application and run it in Tomcat Server in IntelliJ IDEA. http://wiki.jetbrains.net/intellij/Creating_a_simple_Web_application_and_deploying_it_to_Tomcat.

    Step 16 - Create a new Web Aplication Prject in IDEA

    Step 17 - Create a new JSP file in it and name it as marksGraph.jsp.

    Step 18 - Change the index.jsp as follows.


    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    
    <html>
      <head>
        <title></title>
      </head>
      <body>
        <a href="marksGraph.jsp">Show Students Marks Graph</a>
      </body>
    </html>

    Step 19- Download all these jars and add the to the lib folder inside your project - > web folder - > WEB-INF folder. Also add the jasperreports jar to the dependencies folder of your project.
    Step 20 - Add the previously saved jrxml file to the web folder of your project.

    Step 21 - Change the marksGraph.jsp as follows.

    This code is responsible for load the jrxml file and generate the report. Also it writes the report to the web page as a PDF.

    <%@ page contentType="application/pdf" %>
    
    <%@ page trimDirectiveWhitespaces="true"%>
    
    <%@ page import="net.sf.jasperreports.engine.*" %>
    <%@ page import="java.io.File" %>
    <%@ page import="java.io.FileInputStream" %>
    <%@ page import="java.io.FileNotFoundException" %>
    <%@ page import="java.io.InputStream" %>
    <%@ page import="java.sql.Connection" %>
    <%@ page import="java.sql.DriverManager" %>
    <%@ page import="java.sql.SQLException" %>
    
    <%
        Connection conn=null;
         try {
            //Connecting to the MySQL database
    
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/Students?user=root&password=12345");
    
            //Loading Jasper Report File from Local file system
    
            String jrxmlFile = session.getServletContext().getRealPath(request.getContextPath())+"/GenerateReport.jrxml";
            InputStream input = new FileInputStream(new File(jrxmlFile));
    
            //Generating the report
    
            JasperReport jasperReport = JasperCompileManager.compileReport(input);
            JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, null, conn);
    
            //Exporting the report as a PDF
    
            JasperExportManager.exportReportToPdfStream(jasperPrint, response.getOutputStream());
    
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (JRException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        finally {
            if(conn!=null){
                conn.close();
            }
        }
    %>
    

    Step 22 - Cick on the run button to run this web application in Tomcat Server.



    Step 23 - The newly deployed web application will be displyed in the web page like this,



    Step 24 - Click on the Show Student Marks Graph link.

    Step 25 - The students marks graph will be shown as a PDF like this,




    Also please note that after saving the jrxml file using iReport designer, remove all the uuid tags of each and every element. Also you can use this kind of report generation logic in any web application. I have attached the source code of my sample web app here. https://www.dropbox.com/s/d8tk1midq4tdy7e/ReportGenerationWebApp.zip Hope this tutorial helped you. Comments and questions are welcomed.

    Sunday, October 14, 2012

    Optimized Light Weight XPATH Parser using AXIOM and Antlr Parser Generator

    If we talk about parsing a XPath expression we can use the XPath engines like Jaxen or AXIOM XPath which is built on top of AXIOM. These XPath engines supports the full specification of XPath.
    But most of the time our use-case is not having the full XPath specification parsing support but a quick and optimized way of parsing XPath. Because most of the time we are parsing XPath expressions like "/data/book/name", which will point to a single element of a XML.
    So If we have some-kind of fact that we want the first match of XPath or we have only one match for XPath expression, we don't need to open the full tree of XML.
    For a example to parse an XPath expression like "/data/book/author/name" against following XML, we don't have to look at lecturers element at all.
    
      
           
       Andun
       Sri Lanka
           
      
      
           
               Mr_Thilak_Fernando
               
                   108
                   328
                   568
               
          
          
               Ms_Pivithuru
               
                   88
                   328
                   568
                   808
                   1048
               
          
          
               Mr_Nisansa
               
                   88
                   328
                   568
                   808
                   1048
               
          
      
    
    So in this post I will describe a implementation of a High Performance Custom Xpath Parser which will have following conditions,
    • Will return the first match of XPAth expression 
    If we have an XPath like, "/data/book/author/name". This parser only return the <name>Andun</name> element only.
    
        
            
            Andun
            Sri Lanka
        
        
        
            
            Sameera
            Sri Lanka
            
        
    
    • Only return a single element as result. No Sets are returned. 
    If we have an XPath like, "/data/book/author/name". This parser only return the <name>Andun</name> element only. While the XPath Spec defines the result of this expression is <name>Andun</name><name>Sameera</name>.
    
        
            
            Andun
            Sri Lanka
        
        
        
            
                
                Sameera
                Sri Lanka
                
            
        
    
    • Only parse absolute XPath expressions. 
    This kind of XPath expression are accepted "/data/book/author/@age" while "//author/name" kind of expressions are rejected.
    • Complex XPath expression which have predicates, logical combinations of results etc. will be not be eligible.
    To implement this we have used this kind of architecture on top of the AXIOM data model for a XML. Created small components which are responsible to do simple operations to AXIOM data model. For Example,
    • Component to return XML node if it matches some conditions.
    • Component to return set of children of a XML node if it matches some conditions.
    • Component to return an attribute of a XML node.
    Each of these components get a OMElement as the input and it will output the result. Also we can specify some conditions to get the result. So joining these components as a chain we can get the result of a XPath expression.


    Here the XML is passed to the first component. Then the result of the first component is passed to the second. Like wise the chain is created. So the result of the final component is the result of the XPath expression.
    So likewise we can create a simple XPath parser. Here the advantages are, 
    • It will not have to do check the all spec of the XPath spec which is useless for most of the use-case. 
    • It don't have to traverse the all big tree of XML to get the result.
    • AXIOM will not load the XML elements to the memory which are not traversed.
    So this new Custom XPath parser will do following,
    • When we give a XPath expression to the parser it will create the component chain which will do the processing to get the result of the XPath.
    • When the parsing happens, the input XML is passed though the component chain and output the result.
    To create the component chain we have analyze the given XPATH expression. For that We use Antlr Parser Generator.
    • We have to check weather the given XPath expression can be evaluated using Parser.
    • If the expression can be parsed, we have to create the above dicribed component chain. 
    We have used a Antlr Grammar for XPath 1.0. Using that grammar we have generated a Lexer, Parser and Walker for  XPath 1.0. When a XPath expression is given Antlr will analyze the expression using the given Grammar which we have created. Then It will generate a Abstract Syntax tree like the following,


    The using this generated tree we are building the  component chain. Each node of this tree is responsible to add some JAVA code to the XPath parser. When the tree is traversed a Java class will be generated. Using that we can parse a XPath expression.
    Also when this tree found a XPath expression which cant be evaluated using our Custom Parser it will throw an Exception. So we can develop a logic to catch that exception and call a XPath parser like Jaxen to do processing.
    Also to further optimize the processing we can use a input stream of a XML. So AXIOM will only read the necessary part of that stream to process the XPath expression.
    Following JAVA class shows the implementation of the XPath parser. Please contact me to further clarifications.

    package org.wso2.carbon.custom_xpath;
    
    import org.antlr.runtime.RecognitionException;
    import org.apache.axiom.om.OMAbstractFactory;
    import org.apache.axiom.om.OMElement;
    import org.apache.axiom.om.impl.builder.StAXOMBuilder;
    import org.apache.axiom.om.impl.llom.util.AXIOMUtil;
    import org.apache.axiom.soap.SOAPEnvelope;
    import org.apache.axiom.soap.SOAPFactory;
    import org.wso2.carbon.custom_xpath.compiler.CustomXPATHCompiler;
    import org.wso2.carbon.custom_xpath.compiler.exception.CustomXPATHCompilerException;
    import org.wso2.carbon.custom_xpath.exception.CustomXPATHException;
    import org.wso2.carbon.custom_xpath.parser.custom.CustomParser;
    import org.wso2.carbon.custom_xpath.parser.custom.components.ParserComponent;
    import javax.xml.namespace.QName;
    import javax.xml.stream.XMLStreamException;
    import java.io.ByteArrayInputStream;
    import java.io.InputStream;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    
    public class CustomXPATH {
    
        private String xPath;
        private CustomParser customParser;
        private HashMap<String,String> prefixNameSpaceMap;
    
        /**
         * This constructor is responsible For Create a Custom XPATH Parser Object
         * @param xPath is the XPATH String
         * @param prefixNameSpaceMap  Prefix:NameSpace Map
         * @throws CustomXPATHException
         */
        public CustomXPATH(String xPath,HashMap<String,String> prefixNameSpaceMap) throws CustomXPATHException {
            setPrefixNameSpaceMap(prefixNameSpaceMap);
            setxPath(xPath);
            try {
                setCustomParser(CustomXPATHCompiler.parse(getxPath()));
            } catch (RecognitionException e) {
                throw new CustomXPATHException(e);
            }
            catch(CustomXPATHCompilerException exception){
                //Here is the catch clause for XPath expressions which the Custom Parser cant process. So we can call A parser like Jaxen here.
            }
        }
    
        /**
         * This will return the XPATH expression's result when you provide a Input Stream To a XML
         * @param inputStream for a XML
         * @return  Result of the XPATH expression
         * @throws XMLStreamException
         * @throws CustomXPATHException
         */
        public  String getStringValue(InputStream inputStream) throws XMLStreamException, CustomXPATHException {
            if(customParser!=null){
                return getCustomParser().process(inputStream);
            }
            else{
                //Here the Jaxen will do the processing
            }
        }
    
        /**
         * This will return the XPATH expression's result when you provide a Input Stream To a XML
         * @param envelope for a XML
         * @return  Result of the XPATH expression
         * @throws XMLStreamException
         * @throws CustomXPATHException
         */
        public  String getStringValue(String envelope) throws XMLStreamException, CustomXPATHException {
            return getStringValue(new ByteArrayInputStream(envelope.getBytes()));
        }
    
        public String getxPath() {
            return xPath;
        }
    
        public void setxPath(String xPath) {
            this.xPath = xPath;
        }
    
        public CustomParser getCustomParser() {
            return customParser;
        }
    
        public void setCustomParser(CustomParser customParser) {
            this.customParser = customParser;
        }
    
        public HashMap<String, String> getPrefixNameSpaceMap() {
            return prefixNameSpaceMap;
        }
    
        public void setPrefixNameSpaceMap(HashMap<String, String> prefixNameSpaceMap) {
            this.prefixNameSpaceMap = prefixNameSpaceMap;
            ParserComponent.setPrefixNameSpaceMap(prefixNameSpaceMap);
        }
    
    }
    

    Thursday, September 6, 2012

    XACML Policy Enforcement Point(PEP) Proxy for WSO2 Identity Server

    As you all know The WSO2 Identity Server provides  entitlement management  by XACML fine-grained policy based access control. In  this post I will introduce a Proxy Components for use this functionality in JAVA applications. This will make the users life easy in following ways,
    • User have to invoke a method in the proxy to get a entitlement decision.
    • User don't have to implement XACML request related things to use a XACML policy hosted in IS. The proxy hides those complexity from user.
    • Entitlement requests can be sent either using XACML 3.0 or  XACML 2.0.
    • The proxy provides list of methods which will most of the authorization request scenarios which a user can have.
    • User can use SOAP, Thrift or JSON to PDP PEP communication. User doesn't have to worry about the communication implementation.
    • Several PEPs can use same Proxy to communicate with several PDPs(WSO2 IS instances) at the same time.
    Following diagram will show the functionality of the PEP Proxy,


    Here XACML PEP can be any JAVA application. I have given a example application in my previous blog posts, http://www.insightforfuture.blogspot.com/2012/07/providing-xacml-fine-grained.html and http://www.insightforfuture.blogspot.com/2012/07/providing-xacml-fine-grained_22.html. In that I have described a Servlet Filter which uses this PEP proxy for give authorization to webapps.

    The following list will show the API methods given in PEP Proxy,
    • String getDecision(Attribute[] attributes)
    • String getDecision(Attribute[] attributes, String appId) 
    • String getDecision(String subject, String resource, String action, String environment)
    • String getDecision(String subject, String resource, String action, String environment, String appId)
    • boolean subjectCanActOnResource(String subjectType, String alias, String actionId,
                                                 String resourceId, String domainId) 
    • boolean subjectCanActOnResource(String subjectType, String alias, String actionId,
                                                 String resourceId, String domainId, String appId)
    • boolean subjectCanActOnResource(String subjectType, String alias, String actionId,
                                                 String resourceId, Attribute[] attributes, String domainId)
    • boolean subjectCanActOnResource(String subjectType, String alias, String actionId,
                                                 String resourceId, Attribute[] attributes, String domainId, String appId)
    • List<String> getActionableChidResourcesForAlias(String alias, String parentResource,
                                                                 String action)
    • List<String> getActionableChidResourcesForAlias(String alias, String parentResource,
                                                                 String action, String appId) 
    • List<String> getResourcesForAlias(String alias)
    • List<String> getResourcesForAlias(String alias, String appId)
    • List<String> getActionableResourcesForAlias(String alias)
    • List<String> getActionableResourcesForAlias(String alias, String appId)
    • List<String> getActionsForResource(String alias, String resources)
    • List<String> getActionsForResource(String alias, String resources, String appId)
    Here you can see that there are duplicates of same method with "String appId" and without. When the proxy is initialized it will assign a default primary PEP as defaultAppId. That means the PDP mapping for the defaultAppId is used for make the queries. When  we specify a specific PEP configuration by giving "String appId", PEP Proxy will use those configuration to make the quires from WSO2 IS. All the methods which doesn't have "String appId" argument will use the default configuration.

    Following JAVA class will give a example to use PEP Proxy. I used a Sample XACML policy hosted in WSO IS. That policy is given below Also,

    JAVA Class :

    package org.wso2.carbon.identity.entitlement.proxy;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class Test {
    
    
        public static void main(String arg[]) throws Exception {
    
            PEPProxy pepProxy;
            //Initializing the PEP Proxy
    
            System.setProperty("javax.net.ssl.trustStore", "wso2carbon.jks");
            System.setProperty("javax.net.ssl.trustStorePassword", "wso2carbon");
    
            Map<String,Map<String,String>> appToPDPClientConfigMap = new HashMap<String, Map<String,String>>();
    
            //Configuration to Initialize SOAP Client
            Map<String,String> clientConfigMapSOAP = new HashMap<String, String>();
            clientConfigMapSOAP.put("client", "soap");
            clientConfigMapSOAP.put("serverUrl", "https://localhost:9443/services");
            clientConfigMapSOAP.put("userName", "admin");
            clientConfigMapSOAP.put("password", "admin");
            clientConfigMapSOAP.put("reuseSession", "false");
    
            appToPDPClientConfigMap.put("SOAP_APP", clientConfigMapSOAP);
    
            //Configuration to Initialize Basic Authentication Client
            Map<String,String> clientConfigMapBasicAuth = new HashMap<String, String>();
            clientConfigMapBasicAuth.put("client", "basicAuth");
            clientConfigMapBasicAuth.put("serverUrl", "https://localhost:9443/services");
            clientConfigMapBasicAuth.put("userName", "admin");
            clientConfigMapBasicAuth.put("password", "admin");
    
            appToPDPClientConfigMap.put("BasicAuth_APP", clientConfigMapBasicAuth);
    
            //Configuration to Initialize Thrift Client
            Map<String,String> clientConfigMapThrift = new HashMap<String, String>();
            clientConfigMapThrift.put("client", "soap");
            clientConfigMapThrift.put("serverUrl", "https://localhost:9443/services");
            clientConfigMapThrift.put("userName", "admin");
            clientConfigMapThrift.put("password", "admin");
            clientConfigMapThrift.put("reuseSession", "false");
            clientConfigMapThrift.put("thriftHost", "localhost");
            clientConfigMapThrift.put("thriftPort", "10500");
    
            appToPDPClientConfigMap.put("Thrift_App", clientConfigMapThrift);
    
    
            PEPProxyConfig config = new PEPProxyConfig(appToPDPClientConfigMap,"SOAP_APP", "Simple", 10000, 100);
            pepProxy = new PEPProxy(config);
    
            String result = pepProxy.getDecision("admin", "/Entitlement_Sample_WebApp/protected.jsp", "GET", "");
            System.out.println(result);
            result = pepProxy.getDecision("admin", "/Entitlement_Sample_WebApp/protected.jsp", "GET", "", "BasicAuth_APP");
            System.out.println(result);
            result = pepProxy.getDecision("admin", "/Entitlement_Sample_WebApp/protected.jsp", "GET", "", "Thrift_App");
            System.out.println(result);
            boolean bResult = pepProxy.subjectCanActOnResource("urn:oasis:names:tc:xacml:1.0:subject:subject-id", "admin", "GET", "/Entitlement_Sample_WebApp/protected.jsp", "");
            System.out.println(bResult);
        }
    }
    
    Samples XACML Policy :

    <Policy xmlns="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17"  PolicyId="Entitlement_Filter_Sample_Policy" RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable" Version="1.0">
        <Target></Target>
        <Rule Effect="Permit" RuleId="Rule1">
            <Target>
                <AnyOf>
                    <AllOf>
                        <Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                            <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">/Entitlement_Sample_WebApp/protected.jsp</AttributeValue>
                            <AttributeDesignator AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id" Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true"></AttributeDesignator>
                        </Match>
                        <Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                            <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">GET</AttributeValue>
                            <AttributeDesignator AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id" Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true"></AttributeDesignator>
                        </Match>
                        <Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                            <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">admin</AttributeValue>
                            <AttributeDesignator AttributeId="urn:oasis:names:tc:xacml:1.0:subject:subject-id" Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject" DataType="http://www.w3.org/2001/XMLSchema#string" MustBePresent="true"></AttributeDesignator>
                        </Match>
                    </AllOf>
                </AnyOf>
            </Target>
        </Rule>
    </Policy>         
    
    
    To test the PEP Proxy, You can do following steps,
    • Run a WSO2 IS Server 
    • Host the given sample policy
    • Run this Java Class with the dependency jar of PEPProxy. You can get that by building the source given below. That will give you the latest jar of PEPProxy. What you have to do is run mvn clean install in the source folder.
    You can find the source of the PEP proxy in http://wso2.org/svn/browse/wso2/carbon/platform/trunk/components/identity/org.wso2.carbon.identity.entitlement.proxy/.I think this post helps you a lot to use IS inf future works.Also contact me if you have any problem. this was a Internship project of me at WSO2.  Please read following to have better understanding about WSO2 IS and related stuff.