/* * DO NOT REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 2013 ForgeRock Inc. All rights reserved. * * The contents of this file are subject to the terms * of the Common Development and Distribution License * (the License). You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://forgerock.org/license/CDDLv1.0.html * See the License for the specific language governing * permission and limitations under the License. * * When distributing Covered Code, include this CDDL * Header Notice in each file and include the License file * at http://forgerock.org/license/CDDLv1.0.html * If applicable, add the following below the CDDL Header, * with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" */ package org.forgerock.openicf.connectors.rsaauthenticationmanager; import com.rsa.admin.SearchPrincipalsCommand; import com.rsa.admin.SearchRealmsCommand; import com.rsa.admin.data.IdentitySourceDTO; import com.rsa.admin.data.PrincipalDTO; import com.rsa.admin.data.RealmDTO; import com.rsa.admin.data.SecurityDomainDTO; import com.rsa.command.ClientSession; import com.rsa.command.CommandException; import com.rsa.command.CommandTargetPolicy; import com.rsa.command.Connection; import com.rsa.command.ConnectionFactory; import com.rsa.command.InvalidSessionException; import com.rsa.command.exception.DataNotFoundException; import com.rsa.command.exception.InsufficientPrivilegeException; import com.rsa.command.exception.InvalidArgumentException; import com.rsa.common.search.Filter; import java.io.FileOutputStream; import java.io.IOException; import java.security.GeneralSecurityException; import java.util.Properties; import org.identityconnectors.common.logging.Log; /** * Class to represent a RSA AM 8 Connector Connection. * * @author Alex Babeanu (ababeanu@nulli.com) * www.nulli.com - Identity Solution Architects * * @version 1.1 * @since 1.0 */ public class RSAAuthenticationManager8Connection { /** * An instance of the RSA Configuration */ private RSAAuthenticationManager8Configuration configuration; /** * An instance of a Connection to the RSA Server */ private ClientSession RSAsession; /** * The RSA Security Domain */ private final SecurityDomainDTO domain; /** * The RSA IS Source */ private final IdentitySourceDTO idSource; /** * Setup logging for the {@link RSAAuthenticationManager8Connection}. */ private static final Log logger = Log.getLog(RSAAuthenticationManager8Connection.class); /** * Constructor of RSAAuthenticationManager8Connection class. * * @param configuration the actual {@link RSAAuthenticationManager8Configuration} */ public RSAAuthenticationManager8Connection(RSAAuthenticationManager8Configuration configuration) { this.configuration = configuration; // Validate the configuration try { logger.info("Validating configuration..."); this.configuration.validate(); logger.info("The configuration is valid."); } catch (IllegalArgumentException iae) { logger.error("The given configuration failed validation with exception: " + iae.getMessage() + " - " + iae.getCause()); } // Create a config.properties file for RSA SDK, uncommente if needed. /* */ if (!(this.configuration.getConfigFileExists())) { logger.info("Missing configuration file, creating a new one..."); createConfigPropertiesFile(); logger.info("Config file created."); } /* */ // establish a connected session with given credentials logger.info("Attempting to connect to the RSA AM Server..."); Connection conn = ConnectionFactory.getConnection("CommandAPIConnection"); // "CommandAPIConnection" // createConfigProperties() logger.info ("Connection instantiated. Attempting to login..."); String PlainPwd = RSAAuthenticationManager8Utils.getPlainPassword(this.configuration.getUserMgrPwd()); try { this.RSAsession = conn.connect(this.configuration.getUserMgrPrincipal(), PlainPwd); logger.info("Connection succeeded: {0}", this.RSAsession.getSessionId()); } catch (CommandException e) { logger.error("Failed to connect to the RSA server. Error: " + e.getMessage() + " key: " +e.getMessageKey() + " cause: " + e.getCause() + "\n User: " + this.configuration.getUserMgrPrincipal() + " - Pwd: " + PlainPwd); throw new org.identityconnectors.framework.common.exceptions.ConnectionFailedException(e); } // make all commands execute using this target automatically //CommandTargetPolicy.setDefaultCommandTarget(this.RSAsession); logger.info("Using session with ID: {0}.", this.RSAsession.getSessionId()); // Fetch the Security Domain DTO and search for the ID Source by querying the RSA Security realm // First determine whether the connector was instantiated with a specific Domain ID, else use // the default ("SystemDomain"). String DomainString = null; String CfgDomainString = this.configuration.getSecurityDomain(); if (CfgDomainString == null) DomainString = RSAAuthenticationManager8Configuration.RSA_DOMAIN; else { logger.info ("Using Security Domain {0}...", CfgDomainString); DomainString = CfgDomainString; } SearchRealmsCommand searchRealmCmd = new SearchRealmsCommand(); searchRealmCmd.setFilter(Filter.equal(RealmDTO.NAME_ATTRIBUTE, DomainString)); logger.info("Searching for RSA SecurityDomain with filter: " + searchRealmCmd.getFilter().toString()); try { searchRealmCmd.execute(RSAsession); this.sessionLogout(RSAsession); } catch (InsufficientPrivilegeException e) { logger.error("Insufficient Privileges to create Principal: " + e.getMessage() + " User ID: " + configuration.getCmdclientUser()); throw new RuntimeException ("Insufficient Privileges to create Principal", e); } catch (DataNotFoundException e) { logger.error("Could not find the RSA Security Domain: " + DomainString + " - " + e.getMessage() + " key: " +e.getMessageKey() + " cause: " + e.getCause()); throw new RuntimeException ("Could not find the RSA Security Domain: ", e); } catch (InvalidArgumentException e) { logger.error("Invalid Argument for Domain search: " + DomainString + " - " + e.getMessage() + " key: " +e.getMessageKey() + " cause: " + e.getCause()); throw new RuntimeException ("Invalid Argument for Domain search: ", e); } catch (InvalidSessionException e) { logger.error("Invalid Session - " + e.getMessage()); throw new RuntimeException ("Invalid Session", e); } catch (CommandException e) { logger.error("An exception was thrown by the RSA command: " + e.getMessage() + " key: " +e.getMessageKey() + " cause: " + e.getCause()); throw new RuntimeException ("An exception was thrown by the RSA command: ", e); } RealmDTO[] realms = searchRealmCmd.getRealms(); if (realms.length == 0) { // ERROR: TODO: throw new Exception("ERROR: Could not find realm SystemDomain"); domain = null; idSource = null; logger.error("Unable to find any RSA Security Realm"); throw new IllegalArgumentException ("Failed to find the requested RSA Security Domain: " + DomainString + " - with filter: " + searchRealmCmd.getFilter().toString()); } else { domain = realms[0].getTopLevelSecurityDomain(); idSource = realms[0].getIdentitySources()[0]; logger.info("Found RSA SecurityDomain: " + domain.getName()); logger.info("Found RSA ID Source: " + idSource.getName()); } } /** * Gets the RSA Session object from the connection. * * @return a RSA Session object. */ public ClientSession getRSASession () { return this.RSAsession; } /** * Gets the RSA ID Source for the current connection * * @return An Identity Source object */ public IdentitySourceDTO getIdSource () { return this.idSource; } /** * Gets the RSA Security Domain for the current connection * @return an instance of a Domain */ public SecurityDomainDTO getDomain () { return this.domain; } /** * Release internal resources. */ public void dispose() { logger.info("Disposing Connection"); try { this.RSAsession.logout(); logger.info("Successful Logout"); } catch (CommandException e) { logger.info("Failed to Logout of the RSA server. Error: " + e.getMessage() + " key: " +e.getMessageKey() + " cause: " + e.getCause()); } this.RSAsession = null; } /** * If internal connection is not usable, throw IllegalStateException. */ public void test() { // establish a connected session with given credentials logger.info("Performing Connection Test"); logger.info("Connection Session ID {0}:", this.RSAsession.getSessionId()); logger.info("Connection domain name {0}:", this.domain.getName()); logger.info("Connection ID Source {0}:", this.idSource); /*Connection conn = ConnectionFactory.getConnection("CommandAPIConnection" ); // "CommandAPIConnection" // createConfigProperties() try { this.RSAsession = conn.connect(this.configuration.getUserMgrPrincipal(), RSAAuthenticationManager8Utils.getPlainPassword(this.configuration.getUserMgrPwd())); } catch (CommandException e) { logger.error("Failed to connect to the RSA server. Error: " + e.getMessage() + " key: " + e.getMessageKey() + " cause: " + e.getCause()); throw new IllegalStateException(e); //org.identityconnectors.framework.common.exceptions.ConnectionFailedException(e); }*/ try { // as test, query self to see if there is proper response SearchPrincipalsCommand cmd = new SearchPrincipalsCommand(); cmd.setLimit(RSAAuthenticationManager8Configuration.SEARCH_LIMIT_DEFAULT); cmd.setIdentitySourceGuid(getIdSource().getGuid()); cmd.setSecurityDomainGuid(getDomain().getGuid()); cmd.setAttributeMask(new String[]{"CORE_ATTRIBUTES"}); cmd.setFilter(Filter.equal(PrincipalDTO.LOGINUID, configuration.getUserMgrPrincipal())); cmd.setSearchSubDomains(true); ClientSession ses = this.newSession(); cmd.execute(ses); this.sessionLogout(ses); logger.info("Connection Test Successful"); } catch (Exception e) { logger.warn("Connection Test Failed"); throw new IllegalStateException ("RSA Connection failed", e); } } /** * Private Methods */ /** * Creates a RSA connection configuration Properties file using the properties manually set in the Connector \ * Configuration object. It also encrypts all the configuration properties. */ private void createConfigPropertiesFile () { Properties prop = new Properties(); try { //set the encrypted properties value prop.setProperty("java.naming.factory.initial", RSAAuthenticationManager8Utils.encrypt(this.configuration.getInitialNamingFactory())); prop.setProperty("java.naming.provider.url", RSAAuthenticationManager8Utils.encrypt(this.configuration.getNamingProviderUrl())); prop.setProperty("com.rsa.cmdclient.user", RSAAuthenticationManager8Utils.encrypt(this.configuration.getCmdclientUser())); prop.setProperty("com.rsa.cmdclient.user.password", RSAAuthenticationManager8Utils.encrypt(RSAAuthenticationManager8Utils.getPlainPassword(this.configuration.getCmdClientUserPwd()))); prop.setProperty("com.rsa.ssl.client.id.store.password", RSAAuthenticationManager8Utils.encrypt(RSAAuthenticationManager8Utils.getPlainPassword(this.configuration.getRsaSslClientIdStorePwd()))); prop.setProperty("com.rsa.ssl.client.id.key.password", RSAAuthenticationManager8Utils.encrypt(RSAAuthenticationManager8Utils.getPlainPassword(this.configuration.getRsaSslClientIdKeyPwd()))); prop.setProperty("ims.ssl.client.provider.url", RSAAuthenticationManager8Utils.encrypt(this.configuration.getImsSslClientProviderUrl())); prop.setProperty("ims.ssl.client.identity.keystore.filename", RSAAuthenticationManager8Utils.encrypt(this.configuration.getImsSslClientIdentityKeystoreFilename())); prop.setProperty("ims.ssl.client.identity.key.alias", RSAAuthenticationManager8Utils.encrypt(this.configuration.getImsSslClientIdentityKeyAlias())); prop.setProperty("ims.ssl.client.root.ca.alias", RSAAuthenticationManager8Utils.encrypt(this.configuration.getImsSslClientRootCaAlias())); //prop.setProperty("ims.soap.client.provider.url", RSAAuthenticationManager8Utils.encrypt(this.configuration.getImsSoapClientProviderUrl())); prop.setProperty("ims.httpinvoker.client.provider.url", RSAAuthenticationManager8Utils.encrypt(this.configuration.getImsHttpinvokerClientProviderUrl())); //save properties to project root folder prop.store(new FileOutputStream(RSAAuthenticationManager8Configuration.CONFIG_PROPERTIES_FILE), "Auto-generated properties file storing the RSA Connectivity params."); logger.info("Succesfully created the RSA connectivity config properties file!"); } catch (IOException ex) { logger.error("Unable to create configuration properties file: " + RSAAuthenticationManager8Configuration.CONFIG_PROPERTIES_FILE); } catch (GeneralSecurityException ex) { logger.error("An exception occured while encrypting the configuration properties."); throw new RuntimeException ("An Encryption exception occured.", ex); } } /** * Creates a Properties object that contains the RSA connection configuration. * This method DOES NOT encrypt the properties as the resulting Properties object * is not expected to be persisted but used right away as a memory construct. * * @return a Properties object. */ private Properties createConfigProperties() { Properties prop = new Properties(); //set the properties value prop.setProperty("java.naming.factory.initial", this.configuration.getInitialNamingFactory()); prop.setProperty("java.naming.provider.url", this.configuration.getNamingProviderUrl()); prop.setProperty("com.rsa.cmdclient.user", this.configuration.getCmdclientUser()); prop.setProperty("com.rsa.cmdclient.user.password", RSAAuthenticationManager8Utils.getPlainPassword(this.configuration.getCmdClientUserPwd())); prop.setProperty("com.rsa.ssl.client.id.store.password", RSAAuthenticationManager8Utils.getPlainPassword(this.configuration.getRsaSslClientIdStorePwd())); prop.setProperty("com.rsa.ssl.client.id.key.password", RSAAuthenticationManager8Utils.getPlainPassword(this.configuration.getRsaSslClientIdKeyPwd())); prop.setProperty("ims.ssl.client.provider.url", this.configuration.getImsSslClientProviderUrl()); prop.setProperty("ims.ssl.client.identity.keystore.filename", this.configuration.getImsSslClientIdentityKeystoreFilename()); prop.setProperty("ims.ssl.client.identity.key.alias", this.configuration.getImsSslClientIdentityKeyAlias()); prop.setProperty("ims.ssl.client.root.ca.alias", this.configuration.getImsSslClientRootCaAlias()); //prop.setProperty("ims.soap.client.provider.url", this.configuration.getImsSoapClientProviderUrl()); //prop.setProperty("ims.httpinvoker.client.provider.url", this.configuration.getImsHttpinvokerClientProviderUrl()); logger.info("Succesfully created the RSA connectivity config properties."); return prop; } /** * Creates and returns a brand new connection (rather than pooled/cached connection). * This may be preferable to use with some commands * * @return a ClientSession. */ public ClientSession newSession() { ClientSession newSession; logger.info("Creating a new Session"); // establish a connected session with given credentials Connection conn = ConnectionFactory.getConnection("CommandAPIConnection"); // "CommandAPIConnection" // createConfigProperties() logger.info ("Connection instantiated. Attempting to login..."); String PlainPwd = RSAAuthenticationManager8Utils.getPlainPassword(this.configuration.getUserMgrPwd()); try { newSession = conn.connect(this.configuration.getUserMgrPrincipal(), PlainPwd); logger.info("Connection succeeded: {0}", newSession.getSessionId()); } catch (CommandException e) { logger.error("Failed to connect to the RSA server. Error: " + e.getMessage() + " key: " +e.getMessageKey() + " cause: " + e.getCause() + "\n User: " + this.configuration.getUserMgrPrincipal() + " - Pwd: " + PlainPwd); throw new org.identityconnectors.framework.common.exceptions.ConnectionFailedException(e); } return newSession; } /** * fetches the Realm data for a given connection. * To use in conjunction with newConnection() * * @return a RealmDTO. */ public RealmDTO getSessionRealm(ClientSession session) { // Fetch the Security Domain DTO and search for the ID Source by querying the RSA Security realm // First determine whether the connector was instantiated with a specific Domain ID, else use // the default ("SystemDomain"). String DomainString = null; String CfgDomainString = this.configuration.getSecurityDomain(); if (CfgDomainString == null) { DomainString = RSAAuthenticationManager8Configuration.RSA_DOMAIN; } else { logger.info ("Using Security Domain {0}...", CfgDomainString); DomainString = CfgDomainString; } SearchRealmsCommand searchRealmCmd = new SearchRealmsCommand(); searchRealmCmd.setFilter(Filter.equal(RealmDTO.NAME_ATTRIBUTE, DomainString)); logger.info("Searching for RSA SecurityDomain with filter: " + searchRealmCmd.getFilter().toString()); try { searchRealmCmd.execute(session); } catch (InsufficientPrivilegeException e) { logger.error("Insufficient Privileges to create Principal: " + e.getMessage() + " User ID: " + configuration.getCmdclientUser()); throw new RuntimeException ("Insufficient Privileges to create Principal", e); } catch (DataNotFoundException e) { logger.error("Could not find the RSA Security Domain: " + DomainString + " - " + e.getMessage() + " key: " +e.getMessageKey() + " cause: " + e.getCause()); throw new RuntimeException ("Could not find the RSA Security Domain: ", e); } catch (InvalidArgumentException e) { logger.error("Invalid Argument for Domain search: " + DomainString + " - " + e.getMessage() + " key: " +e.getMessageKey() + " cause: " + e.getCause()); throw new RuntimeException ("Invalid Argument for Domain search: ", e); } catch (InvalidSessionException e) { logger.error("Invalid Session - " + e.getMessage()); throw new RuntimeException ("Invalid Session", e); } catch (CommandException e) { logger.error("An exception was thrown by the RSA command: " + e.getMessage() + " key: " +e.getMessageKey() + " cause: " + e.getCause()); throw new RuntimeException ("An exception was thrown by the RSA command: ", e); } RealmDTO[] realms = searchRealmCmd.getRealms(); if (realms.length == 0) { // ERROR: TODO: throw new Exception("ERROR: Could not find realm SystemDomain"); logger.error("Unable to find any RSA Security Realm"); throw new IllegalArgumentException ("Failed to find the requested RSA Security Domain: " + DomainString + " - with filter: " + searchRealmCmd.getFilter().toString()); } else { SecurityDomainDTO domain = realms[0].getTopLevelSecurityDomain(); IdentitySourceDTO idSource = realms[0].getIdentitySources()[0]; logger.info("Found Realm with RSA SecurityDomain: " + domain.getName()); logger.info("Found Realm with RSA ID Source: " + idSource.getName()); return realms[0]; } } /** * Session Logout */ public void sessionLogout(ClientSession session) { logger.info("closing Connection ID: {0}", session.getSessionId()); try { this.RSAsession.logout(); logger.info("Successful Logout"); } catch (CommandException e) { logger.info("Failed to Logout of the RSA server. Error: " + e.getMessage() + " key: " +e.getMessageKey() + " cause: " + e.getCause()); } } }