Search code examples
ibm-mobilefirstdatabase-connectionadapter

Why does apache.commons.dbcp.BasicDataSource disable SSO in MobileFirst adapter?


I am using the MobileFirst UserLogin sample adapter for SecurityCheck. I want to implement Single Sign On (SSO)

With the clean adapter downloaded from Github, SSO works fine. But I want to validate the credentials against a mysql database. I have noticed that as soon as I add the line

dataSource = new BasicDataSource();

in validateCredentials method, the SSO stops working:

    @Override
    protected boolean validateCredentials(Map<String, Object> credentials) {
        if(credentials!=null && credentials.containsKey("username") && credentials.containsKey("password")){
            String username = credentials.get("username").toString();
            String password = credentials.get("password").toString();

            dataSource = new BasicDataSource(); //this line

            if(!username.isEmpty() && !password.isEmpty() && username.equals(password)) {
                ...

I can still login using this adapter, but SSO does not work anymore.

Complete adapter:

adapter.xml:

<?xml version="1.0" encoding="UTF-8"?>

<mfp:adapter name="UserLogin"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:mfp="http://www.ibm.com/mfp/integration"
    xmlns:http="http://www.ibm.com/mfp/integration/http">

    <displayName>UserLogin</displayName>
    <description>Protect resources using a combination of username and password.</description>

    <securityCheckDefinition name="UserLogin" class="com.sample.UserLogin">
        <property name="maxAttempts" defaultValue="3" description="How many attempts are allowed" type="integer"/>
        <property name="blockedStateExpirationSec" defaultValue="10" description="How long before the client can try again (seconds)" type="integer"/>
        <property name="successStateExpirationSec" defaultValue="60" description="How long is a successful state valid for (seconds)" type="integer"/>
        <property name="rememberMeDurationSec" defaultValue="120" description="How long is the user remembered when using RememberMe (seconds)" type="integer"/>
    </securityCheckDefinition>

</mfp:adapter>

UserLogin.java:

package com.sample;

import com.ibm.mfp.security.checks.base.UserAuthenticationSecurityCheck;
import com.ibm.mfp.server.registration.external.model.AuthenticatedUser;
import org.apache.commons.dbcp.BasicDataSource;

import java.util.HashMap;
import java.util.Map;
import java.sql.*;

public class UserLogin extends UserAuthenticationSecurityCheck {
    private String userId, displayName;
    private String errorMsg;
    private boolean rememberMe = false;
    public BasicDataSource dataSource = null;

    @Override
    protected AuthenticatedUser createUser() {
        return new AuthenticatedUser(userId, displayName, this.getName());
    }

    @Override
    protected boolean validateCredentials(Map<String, Object> credentials) {
        if(credentials!=null && credentials.containsKey("username") && credentials.containsKey("password")){
            String username = credentials.get("username").toString();
            String password = credentials.get("password").toString();

            dataSource = new BasicDataSource();

            if(!username.isEmpty() && !password.isEmpty() && username.equals(password)) {
                userId = username;
                displayName = username;

                //Optional RememberMe
                if(credentials.containsKey("rememberMe") ){
                    rememberMe = Boolean.valueOf(credentials.get("rememberMe").toString());
                }
                errorMsg = null;
                return true;
            }
            else {
                errorMsg = "Wrong Credentials";
            }
        }
        else{
            errorMsg = "Credentials not set properly";
        }
        return false;
    }

    @Override
    protected Map<String, Object> createChallenge() {
        Map challenge = new HashMap();
        challenge.put("errorMsg",errorMsg);
        challenge.put("remainingAttempts",getRemainingAttempts());
        return challenge;
    }

    @Override
    protected boolean rememberCreatedUser() {
        return rememberMe;
    }
}

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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>com.sample</groupId>
    <artifactId>UserLogin</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>adapter</packaging>
    <name>UserLogin</name>

    <dependencies>
        <dependency>
            <groupId>com.ibm.mfp</groupId>
            <artifactId>adapter-maven-api</artifactId>
            <scope>provided</scope>
            <version>[8.0.0,9.0.0)</version>
        </dependency>
        <dependency>
            <groupId>com.ibm.mfp</groupId>
            <artifactId>mfp-security-checks-base</artifactId>
            <version>[8.0.0,9.0.0)</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.2.2</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.4</version>
        </dependency>
    </dependencies>

    <properties>
        <!-- Use UTF-8 as the encoding of the adapter -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <!-- parameters for deploy mfpf adapter -->
        <mfpfUrl>http://localhost:9080/mfpadmin</mfpfUrl>
        <mfpfUser>admin</mfpfUser>
        <mfpfPassword>admin</mfpfPassword>
        <mfpfRuntime>mfp</mfpfRuntime>
        <mfpfRuntime>mfp</mfpfRuntime>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>com.ibm.mfp</groupId>
                <artifactId>adapter-maven-plugin</artifactId>
                <extensions>true</extensions>
            </plugin>
        </plugins>
    </build>
</project>

Solution

  • Use BasicDataSource as transient. Basically when you implement MFP security check, any object that you would not need to as part of Security Check, mark them transient to ensure it is not getting saved as a part of securitycheck state.