Sunday, January 10, 2016

Creating WSO2 IS Custom Federated Authenticator

WSO2 IS custom authenticators provides you a way to authenticate the user using specific external authentication system. through the authenticators we can secure our systems. Before start development Research the APIs provided by the service for which you want to create an authenticator.






  1. Create a folder name called Sample
  2. within folder generate archetype. then you will get the archetype like in image
mvn archetype:generate -DarchetypeGroupId=org.wso2.carbon.extension.archetype -DarchetypeArtifactId=org.wso2.carbon.extension.is.authenticator-archetype -DarchetypeVersion=2.0.0 -DgroupId=org.wso2.carbon.extension.identity.authenticator -DartifactId=org.wso2.carbon.extension.identity.authenticator. -Dversion=1.0.0 -DarchetypeRepository=http://maven.wso2.org/nexus/content/repositories/wso2-public//





The following code block represents the structure of an authenticator pom.xml. Authenticators are basically OSGi (Open Service Gateway initiative) bundles, which are units of modularization that are comprised of Java classes and other resources that provide functions to end users. The pom.xml includes the dependencies for the project.


<?xml version="1.0" encoding="UTF-8"?>
<!--
 ~ Copyright (c) 2016 WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 ~
 ~ Licensed under the Apache License, Version 2.0 (the "License");
 ~ you may not use this file except in compliance with the License.
 ~ You may obtain a copy of the License at
 ~
 ~      http://www.apache.org/licenses/LICENSE-2.0
 ~
 ~ Unless required by applicable law or agreed to in writing, software
 ~ distributed under the License is distributed on an "AS IS" BASIS,
 ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ~ See the License for the specific language governing permissions and
 ~ limitations under the License.
-->

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.wso2.carbon.extension.identity.authenticator</groupId>
    <artifactId>org.wso2.carbon.extension.identity.authenticator.sample</artifactId>
    <version>1.0.0</version>

    <packaging>bundle</packaging>
    <name>WSO2 Carbon - Authenticator Library For Sample</name>
    <url>http://wso2.org</url>
    <dependencies>
        <dependency>
            <groupId>org.wso2.carbon.identity</groupId>
            <artifactId>org.wso2.carbon.idp.mgt</artifactId>
            <version>${carbon.identity.version}</version>
        </dependency>
        <dependency>
            <groupId>org.wso2.carbon</groupId>
            <artifactId>org.wso2.carbon.logging</artifactId>
            <version>${commons-logging.version}</version>
        </dependency>
        <dependency>
            <groupId>org.wso2.carbon.identity</groupId>
            <artifactId>org.wso2.carbon.identity.application.common</artifactId>
            <version>${carbon.identity.version}</version>
        </dependency>
        <dependency>
            <groupId>org.wso2.carbon.identity</groupId>
            <artifactId>org.wso2.carbon.identity.user.profile</artifactId>
            <version>${carbon.identity.version}</version>
        </dependency>
        <dependency>
            <groupId>org.wso2.carbon.identity</groupId>
            <artifactId>org.wso2.carbon.identity.user.account.association</artifactId>
            <version>${carbon.identity.version}</version>
        </dependency>
        <dependency>
            <groupId>org.wso2.carbon.identity</groupId>
            <artifactId>org.wso2.carbon.identity.core</artifactId>
            <version>${carbon.identity.version}</version>
        </dependency>
        <dependency>
            <groupId>org.wso2.carbon.identity</groupId>
            <artifactId>org.wso2.carbon.identity.application.authentication.framework</artifactId>
            <version>${carbon.identity.version}</version>
        </dependency>
        <dependency>
            <groupId>org.wso2.carbon.identity</groupId>
            <artifactId>org.wso2.carbon.identity.notification.mgt</artifactId>
            <version>${carbon.identity.version}</version>
        </dependency>
        <dependency>
            <groupId>org.wso2.carbon.identity</groupId>
            <artifactId>org.wso2.carbon.identity.provisioning</artifactId>
            <version>${carbon.identity.version}</version>
        </dependency>
        <dependency>
            <groupId>org.wso2.carbon</groupId>
            <artifactId>org.wso2.carbon.core</artifactId>
            <version>${carbon.kernel.version}</version>
        </dependency>
        <dependency>
            <groupId>org.wso2.carbon</groupId>
            <artifactId>org.wso2.carbon.user.core</artifactId>
            <version>${carbon.kernel.version}</version>
        </dependency>
        <dependency>
            <groupId>org.wso2.carbon.identity</groupId>
            <artifactId>org.wso2.carbon.identity.application.mgt</artifactId>
            <version>${carbon.identity.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.oltu.oauth2</groupId>
            <artifactId>org.apache.oltu.oauth2.client</artifactId>
            <version>0.31</version>
        </dependency>
        <dependency>
            <groupId>org.apache.oltu.oauth2</groupId>
            <artifactId>org.apache.oltu.oauth2.common</artifactId>
            <version>1.0.1</version>
        </dependency>
        <dependency>
            <groupId>org.wso2.carbon.identity</groupId>
            <artifactId>org.wso2.carbon.identity.application.authenticator.openid</artifactId>
            <version>${carbon.identity.version}</version>
        </dependency>
        <dependency>
            <groupId>org.wso2.carbon.identity</groupId>
            <artifactId>org.wso2.carbon.identity.application.authenticator.oidc</artifactId>
            <version>${carbon.identity.version}</version>
        </dependency>
        <dependency>
            <groupId>org.wso2.carbon</groupId>
            <artifactId>org.wso2.carbon.ui</artifactId>
            <version>${carbon.kernel.version}</version>
        </dependency>
        <dependency>
            <groupId>org.json.wso2</groupId>
            <artifactId>json</artifactId>
            <version>${wso2.json}</version>
        </dependency>
    </dependencies>
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.felix</groupId>
                    <artifactId>maven-bundle-plugin</artifactId>
                    <version>2.3.5</version>
                    <extensions>true</extensions>
                </plugin>
            </plugins>
        </pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.0</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <extensions>true</extensions>
                <configuration>
                    <instructions>
                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
                        <Bundle-Name>${project.artifactId}</Bundle-Name>
                        <Private-Package>org.wso2.carbon.extension.identity.authenticator.internal</Private-Package>
                        <Import-Package>
                            org.apache.commons.logging.*; version="1.0.4",
                            org.osgi.framework,
                            org.wso2.carbon.identity.application.authentication.framework.*,
                            javax.servlet,
                            javax.servlet.http,
                            org.apache.oltu.oauth2.*; version="${oltu.package.import.version.range}",
                            *;resolution:=optional
                        </Import-Package>
                        <Export-Package>
                            !org.wso2.carbon.extension.identity.authenticator.internal,
                            org.wso2.carbon.identity.authenticator.*
                        </Export-Package>
                    </instructions>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-scr-plugin</artifactId>
                <version>1.7.2</version>
                <executions>
                    <execution>
                        <id>generate-scr-scrdescriptor</id>
                        <goals>
                            <goal>scr</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <properties>
        <carbon.identity.version>5.0.7</carbon.identity.version>
        <commons-logging.version>4.4.3</commons-logging.version>
        <carbon.kernel.version>4.4.3</carbon.kernel.version>
        <oltu.version>1.0.0.wso2v2</oltu.version>
        <org.apache.oltu.oauth2.client.version>1.0.0</org.apache.oltu.oauth2.client.version>
        <oltu.package.import.version.range>[1.0.0, 2.0.0)</oltu.package.import.version.range>
        <wso2.json>3.0.0.wso2v1</wso2.json>
    </properties>
</project>

Since the project is an OSGi bundle, you must add this class to define the bundle activate method and deactivate method.

/*
 *  Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 *  WSO2 Inc. licenses this file to you under the Apache License,
 *  Version 2.0 (the "License"); you may not use this file except
 *  in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 *
 */

package org.wso2.carbon.extension.identity.authenticator.internal;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.service.component.ComponentContext;
import org.wso2.carbon.identity.application.authentication.framework.ApplicationAuthenticator;
import org.wso2.carbon.extension.identity.authenticator.SampleAuthenticator;

import java.util.Hashtable;

/**
 * @scr.component name="identity.application.authenticator.Sample.component" immediate="true"
 */
public class SampleAuthenticatorServiceComponent {

    private static Log log = LogFactory.getLog(SampleAuthenticatorServiceComponent.class);

/**
 *
 */
    protected void activate(ComponentContext ctxt) {
        try {
            SampleAuthenticator authenticator = new SampleAuthenticator();
            Hashtable<String, String> props = new Hashtable<String, String>();
            ctxt.getBundleContext().registerService(ApplicationAuthenticator.class.getName(),
                    authenticator, props);
            if (log.isDebugEnabled()) {
                log.debug("Sample authenticator is activated");
            }
        } catch (Throwable e) {
            log.fatal("Error while activating the Sample authenticator ", e);
        }
    }
/**
 *
 */
    protected void deactivate(ComponentContext ctxt) {
        if (log.isDebugEnabled()) {
            log.debug("Sample authenticator is deactivated");
        }
    }
}

/*
 *  Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 *  WSO2 Inc. licenses this file to you under the Apache License,
 *  Version 2.0 (the "License"); you may not use this file except
 *  in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 *
 */

package org.wso2.carbon.extension.identity.authenticator;

public class SampleAuthenticatorConstants {
    public static final String AUTHENTICATOR_NAME = "Sample";
    public static final String AUTHENTICATOR_FRIENDLY_NAME = "SampleAuthenticator";
    //Sample authorize endpoint URL
    public static final String Sample_OAUTH_ENDPOINT = "";
    //Sample token  endpoint URL
    public static final String Sample_TOKEN_ENDPOINT = "";
    //Sample user info endpoint URL
    public static final String Sample_USERINFO_ENDPOINT = "";
}

After adding this to your project, you are in a position to write your authenticator. Authenticators are defined by extending the AbstractApplicationAuthenticator class and implementing the FederatedApplicationAuthenticator interface. The important methods in the AbstractApplicationAuthenticator class and the FederatedApplicationAuthenticator interface are listed as follows.
  • public String getName()
  • public String getFriendlyName()
  • public String getContextIdentifier(HttpServletRequest request) - Returns a unique identifier that will map the authentication request and the response. The value returned by the invocation of authentication request and the response should be the same.
  • public boolean canHandle(HttpServletRequest request) - Specifies whether this authenticator can handle the authentication response.
  • protected void initiateAuthenticationRequest(HttpServletRequest request,HttpServletResponse response, AuthenticationContext context)
  • protected void processAuthenticationResponse(HttpServletRequest request,HttpServletResponse response, AuthenticationContext context)

/*
 *  Copyright (c) 2015, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 *  WSO2 Inc. licenses this file to you under the Apache License,
 *  Version 2.0 (the "License"); you may not use this file except
 *  in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 *
 */

package org.wso2.carbon.extension.identity.authenticator;

import org.apache.oltu.oauth2.client.response.OAuthClientResponse;
import org.wso2.carbon.identity.application.authenticator.oidc.OpenIDConnectAuthenticator;
import org.wso2.carbon.identity.application.authentication.framework.FederatedApplicationAuthenticator;
import org.wso2.carbon.identity.application.common.model.Property;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Authenticator of Sample
 */
public class SampleAuthenticator extends OpenIDConnectAuthenticator
        implements FederatedApplicationAuthenticator {

    private static Log log = LogFactory.getLog(SampleAuthenticator.class);

    /**
     * Get Sample authorization endpoint.
     */
    @Override
    protected String getAuthorizationServerEndpoint(Map< String, String > authenticatorProperties) {
        return SampleAuthenticatorConstants.Sample_OAUTH_ENDPOINT;
    }

    /**
     * Get Sample token endpoint.
     */
    @Override
    protected String getTokenEndpoint(Map< String, String > authenticatorProperties) {
        return SampleAuthenticatorConstants.Sample_TOKEN_ENDPOINT;
    }

    /**
     * Get Sample user info endpoint.
     */
    @Override
    protected String getUserInfoEndpoint(OAuthClientResponse token, Map< String, String > authenticatorProperties) {
        return SampleAuthenticatorConstants.Sample_USERINFO_ENDPOINT;
    }

    /**
     * Check ID token in Sample OAuth.
     */
    @Override
    protected boolean requiredIDToken(Map< String, String > authenticatorProperties) {
        return false;
    }

    /**
     * Get the friendly name of the Authenticator
     */
    @Override
    public String getFriendlyName() {
        return SampleAuthenticatorConstants.AUTHENTICATOR_FRIENDLY_NAME;
    }

    /**
     * Get the name of the Authenticator
     */
    @Override
    public String getName() {
        return SampleAuthenticatorConstants.AUTHENTICATOR_NAME;
    }

    /**
     * Get Configuration Properties
     */
    @Override
    public List<Property> getConfigurationProperties() {

        List<Property> configProperties = new ArrayList<Property>();
        //Add your configuration properties
        return configProperties;
    }
}

  1. Implement the canHandle() method using the above methods. When API sends the OAuth response, it sends the parameters oauth_token and oauth_verifier in the request. This is a notification to identify that this response can be handled by the authenticator.
  2. For each authentication request that comes into the Identity Server, there is unique value that comes along as a parameter. That parameter is the sessionDataKey. Store this in the API authentication redirection session to facilitate the requirement where getContextIdentifier gives the same value for authentication request and its response.
  3. Next, implement the initiateAuthenticationRequest method and the processAuthenticationResponse method.
  4. The buildClaims method saves the retrieved user attributes to the authenticated context in the Identity Server. That is needed to map the claims to the built in claims of IS.
  5. After implementing these methods you can build your bundle. After building it you have to put that into the <IS_HOME>/repository/components/dropins directory.
  6. Restart the Identity Server and configure the authenticators for your identity provider to reach out to third party authentication