Wednesday, September 23, 2015

How WSO2 API Manager gateway to back end secure connection works and troubleshoot SSL gateway issues.

Whenever Java(here in this care WSO2 API Manager act as JVM) attempts to connect to another application over SSL, it will only be able to connect to that application if it can trust it. The way trust is handled in the Java world is that you have a key store (typically $JAVA_HOME/lib/security/cacerts), also known as the trust store. This contains a list of all known Certificate Authority (CA) certificates, and Java will only trust certificates that are signed by one of those CAs or public certificates that exist within that key store.

This problem is therefore caused by a certificate that is self-signed (a CA did not sign it) or a certificate chain that does not exist within the Java key store. Java does not trust the certificate and fails to connect to the application.

We can simply test it with following commands. Here i will use external class to perform SSL poke(class) using our client trust store.

For 1st URL
===========

sanjeewa@sanjeewa-ThinkPad-T530:~/Downloads$ java -Djavax.net.ssl.trustStore=/home/sanjeewa/work/packs/wso2am-1.9.0/repository/resources/security/client-truststore.jks SSLPoke test.com 443
    Successfully connected

For 2nd URL
===========

    sanjeewa@sanjeewa-ThinkPad-T530:~/Downloads$ java -Djavax.net.ssl.trustStore=/home/sanjeewa/work/packs/wso2am-1.9.0/repository/resources/security/client-truststore.jks SSLPoke test-one.com 443
    sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:385)
    at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
    at sun.security.validator.Validator.validate(Validator.java:260)
    at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:326)
    at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:231)
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:126)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1323)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:153)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:868)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:804)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1016)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
    at sun.security.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:702)
    at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:122)
    at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:136)
    at SSLPoke.main(SSLPoke.java:31)
    Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:196)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:268)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380)
    ... 15 more

As you can see first will print "Successfully connected". Then clearly 2nd one is self signed certificate which does not reside in our trust store. And that cause issue here.
Even if we have host name verification or not it doesn't matter here.

Host name verifier will come next.
If we didn't put host name verifier AllowAll in axis2.xml for first end point (https://test.com/posts) then you will see following.

    [2015-09-22 18:36:36,765] ERROR - TargetHandler I/O error: Host name verification failed for host : test.com
    javax.net.ssl.SSLException: Host name verification failed for host : test.com
    at org.apache.synapse.transport.http.conn.ClientSSLSetupHandler.verify(ClientSSLSetupHandler.java:152)
    at org.apache.http.nio.reactor.ssl.SSLIOSession.doHandshake(SSLIOSession.java:285)
    at org.apache.http.nio.reactor.ssl.SSLIOSession.isAppInputReady(SSLIOSession.java:380)
    at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:118)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:160)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:342)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:320)
    at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:280)
    at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:106)
    at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:604)
    at java.lang.Thread.run(Thread.java:745)

During handshaking, if the URL's host name and the server's identification host name mismatch, the verification mechanism can call back to implements of interface(what we have done is override it with property defined in axis2.xml file and return true if property is there) to determine if this connection should be allowed. The policies can be certificate-based or may depend on other authentication schemes. Here second URL failed not because host name issue its failing because its self signed certificate and java does not trusted it. Even first one will fail if we didn't enabled host name verification.

Please refer SSLPoke(class) class for your reference.

Monday, September 14, 2015

How to add 2 step authentication flow to WSO2 APP Manager.

WSO2 App Manager provides a unique one-stop store app management solution where users can pick and choose apps required for them to do their jobs efficiently. Businesses can leverage its single-sign-on (SSO) functionality, which can reduce help desk and administrative costs with no long lists of passwords to memorise. It automatically applies a security layer on top of the web apps published in the store, which eliminates the need to embed security rules at the application layer.

In this article we will discuss how we can add two step authentication when we register service provider.

When you create application in app manager it will call to SSOConfigurator class we defined in app-manager.xml to create service providers.
So i implemented custom class to do it. Class name is TESTIS500SAMLSSOConfigurator and it implemented SSOConfigurator.


Within this class we will create SP and store it. So when we create SP we will add 2 authentication steps.
1. Authentication step to redirect users to Dictao to login system.
2. Then add local authentication step to validate subscriptions and let user to accept terms and conditions if he haven't already done.

We have added few parameters to app-manager.xml to make this configurable. With that new configuration would be something like this. Actually if you need you can add more parameters according to your requirement.

        <Configurators>
            <Configurator>
                <name>wso2is</name>
                <version>5.0.0</version>
        <!--class name of new sso configurator class-->                
        <providerClass>com.test.identity.sso.configurator.customauth.TESTIS500SAMLSSOConfigurator</providerClass>
                <parameters>
                <providerURL>https://is.test.com:9447</providerURL>
                <username>admin</username>
                <password>admin</password>
        <!--IDP name which need to be engage in authentication step 01. You have to create IDP with this name-->    
                <idpName>IDP1</idpName>
        <!--The name of authenticator we should used in step 02. This authenticator is another custom implementation -->    
                <idpStepTwo>TEST-customAuthenticator</idpStepTwo>
            <!--Authentication mechanism of step one--> 
                <authenticationStep>federated</authenticationStep>
                </parameters>
           </Configurator> 




Following code block will be use to add 2 step authentication and engage IDP, Authenticators to authentication flow. You can modify TESTIS500SAMLSSOConfigurator class by adding following.

   if (idpName != null && authenticationStep != null && authenticationStep.equalsIgnoreCase("federated")) {
            if (log.isDebugEnabled()) {
                log.debug("Adding federated authentication step. Added IDP named: " + idpName);
            }
            //Following code will set external IDP as authentication EP
            serviceProvider.getLocalAndOutBoundAuthenticationConfig().setAuthenticationType("flow");
            InboundProvisioningConfig inBoundProConfig = new InboundProvisioningConfig();
            inBoundProConfig.setProvisioningUserStore("");
            serviceProvider.setInboundProvisioningConfig(inBoundProConfig);
            serviceProvider.setOutboundProvisioningConfig(new OutboundProvisioningConfig());
            serviceProvider.setRequestPathAuthenticatorConfigs(null);
            AuthenticationStep[] steps = new AuthenticationStep[2];

            //Add local authenticator
            AuthenticationStep step1 = new AuthenticationStep();
            List<LocalAuthenticatorConfig> localAuthList = new ArrayList<LocalAuthenticatorConfig>();
            LocalAuthenticatorConfig localAuth = new LocalAuthenticatorConfig();
            localAuth.setName(idpStepTwo);
            localAuth.setDisplayName(idpStepTwo);
            localAuth.setEnabled(true);
            localAuthList.add(localAuth);
            step1.setLocalAuthenticatorConfigs(localAuthList.toArray(new LocalAuthenticatorConfig[localAuthList.size()]));
            step1.setStepOrder(2);

            //Add federated authenticator
            AuthenticationStep step = new AuthenticationStep();
            List<IdentityProvider> federatedAuthList = new ArrayList<IdentityProvider>();
            FederatedAuthenticatorConfig federatedAuthenticatorConfig = new FederatedAuthenticatorConfig();
            IdentityProvider identityProvider = new IdentityProvider();
            federatedAuthenticatorConfig.setName("SAMLSSOAuthenticator");
            identityProvider.setIdentityProviderName(idpName);
            identityProvider.setFederatedAuthenticatorConfigs(new FederatedAuthenticatorConfig[]{federatedAuthenticatorConfig});
            identityProvider.setDefaultAuthenticatorConfig(federatedAuthenticatorConfig);
            federatedAuthList.add(identityProvider);
            step.setFederatedIdentityProviders(federatedAuthList.toArray(new IdentityProvider[federatedAuthList.size()]));
            step.setStepOrder(1);
          
             //Here federated authenticator would be added as step 01 and local authenticator would be step 02.
            steps[0] = step;
            steps[1] = step1;
            serviceProvider.setPermissionAndRoleConfig(new PermissionsAndRoleConfig());
            serviceProvider.getLocalAndOutBoundAuthenticationConfig().setAuthenticationSteps(steps);
        } 


       
      
Then once you create application it will automatically register service provider with 2 step authentication.
Once you go to service provider user interface you will see authentication steps as follows.



Complete source code.


https://drive.google.com/file/d/0B3OmQJfm2Ft8LW9TeE5JRW1HU2M/view?usp=sharing

Tuesday, September 1, 2015

How to set password validation policy in WSO2 Identity Server


If you need to add custom password policy there are multiple layers you can add that. First one is user-mgt.xml file and other configuration file is identity-mgt.properties file.

If identity management listener is enabled(only), user passwords should be satisfied both both regrEx defined in user-mgt.xml and identity-mgt.properties files. Otherwise we will check user-mgt.xml to validate password policy.

/repository/conf/user-mgt.xml
         
 <Property name="PasswordJavaRegEx">^[\S]{5,30}$</Property>

Following properties will be picked only if we enabled identity listener(Identity.Listener.Enable=true). Otherwise configurations on user management xml will only affect.

/repository/conf/security/identity-mgt.properties
Password.policy.extensions.1.min.length=6
Password.policy.extensions.1.max.length=12
Password.policy.extensions.3.pattern=^((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%&*])).{0,100}$