/*
* ====================
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of the Common Development
* and Distribution License("CDDL") (the "License"). You may not use this file
* except in compliance with the License.
*
* You can obtain a copy of the License at
* http://opensource.org/licenses/cddl1.php
* See the License for the specific language governing permissions and limitations
* under the License.
*
* When distributing the Covered Code, include this CDDL Header Notice in each file
* and include the License file at http://opensource.org/licenses/cddl1.php.
* If applicable, add the following below this CDDL Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
* ====================
*/
package org.identityconnectors.oracleerp;
import static org.identityconnectors.oracleerp.OracleERPUtil.MSG_ACCOUNT_DISABLED;
import static org.identityconnectors.oracleerp.OracleERPUtil.MSG_AUTH_FAILED;
import static org.identityconnectors.oracleerp.OracleERPUtil.MSG_PASSWORD_EXPIRED;
import static org.identityconnectors.oracleerp.OracleERPUtil.USER_NAME;
import static org.identityconnectors.oracleerp.OracleERPUtil.getColumnValues;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.identityconnectors.common.Assertions;
import org.identityconnectors.common.logging.Log;
import org.identityconnectors.common.security.GuardedString;
import org.identityconnectors.dbcommon.SQLParam;
import org.identityconnectors.dbcommon.SQLUtil;
import org.identityconnectors.framework.common.exceptions.ConnectorException;
import org.identityconnectors.framework.common.exceptions.InvalidCredentialException;
import org.identityconnectors.framework.common.exceptions.InvalidPasswordException;
import org.identityconnectors.framework.common.exceptions.PasswordExpiredException;
import org.identityconnectors.framework.common.objects.ObjectClass;
import org.identityconnectors.framework.common.objects.OperationOptions;
import org.identityconnectors.framework.common.objects.OperationalAttributes;
import org.identityconnectors.framework.common.objects.Uid;
import org.identityconnectors.framework.spi.operations.AuthenticateOp;
import org.identityconnectors.framework.spi.operations.ResolveUsernameOp;
/**
* The AuthenticateOp implementation of the SPI.
*
* @author Petr Jung
* @since 1.0
*/
final class AccountOperationAutenticate extends Operation implements AuthenticateOp,
ResolveUsernameOp {
/**
* @param conn
* @param cfg
*/
AccountOperationAutenticate(OracleERPConnection conn, OracleERPConfiguration cfg) {
super(conn, cfg);
}
private static final Log LOG = Log.getLog(AccountOperationAutenticate.class);
/*
* (non-Javadoc)
*
* @see
* org.identityconnectors.framework.spi.operations.AuthenticateOp#authenticate
* (org.identityconnectors.framework.common.objects.ObjectClass,
* java.lang.String, org.identityconnectors.common.security.GuardedString,
* org.identityconnectors.framework.common.objects.OperationOptions)
*/
public Uid authenticate(ObjectClass objectClass, String username, GuardedString password,
OperationOptions options) {
LOG.ok("authenticate user ''{0}''", username);
Assertions.nullCheck(objectClass, "objectClass");
Assertions.nullCheck(username, "username");
Assertions.nullCheck(password, "password");
createCheckValidateFunction();
// call the validation function
PreparedStatement ps = null;
ResultSet rs = null;
final String sqlAccount =
"select user_name, start_date, end_date, password_date, last_logon_date from "
+ getCfg().app() + "fnd_user where upper(user_name) = ?";
List<SQLParam> par1 = new ArrayList<SQLParam>();
par1.add(new SQLParam(USER_NAME, username.toUpperCase()));
// expired passwords, to the authenticate functionality
AttributeMergeBuilder amb = new AttributeMergeBuilder();
final Uid uid = new Uid(username.toUpperCase());
try {
ps = getConn().prepareCall(sqlAccount, par1);
rs = ps.executeQuery();
if (rs == null || !rs.next()) {
// account not found
throw new InvalidCredentialException(getCfg().getMessage(MSG_AUTH_FAILED, username));
}
final Map<String, SQLParam> columnValues = getColumnValues(rs);
// build special attributes
new AccountOperationSearch(getConn(), getCfg()).buildSpecialAttributes(amb,
columnValues);
// The password is expired
if (amb.hasExpectedValue(OperationalAttributes.PASSWORD_EXPIRED_NAME, 0, Boolean.TRUE)) {
throw new PasswordExpiredException(getCfg().getMessage(MSG_PASSWORD_EXPIRED,
username)).initUid(uid);
}
// The account is disabled
if (amb.hasExpectedValue(OperationalAttributes.ENABLE_NAME, 0, Boolean.FALSE)) {
throw new InvalidPasswordException(getCfg().getMessage(MSG_ACCOUNT_DISABLED,
username));
}
} catch (Exception ex) {
LOG.error(ex, "autenticate exception");
SQLUtil.rollbackQuietly(getConn());
throw ConnectorException.wrap(ex);
} finally {
SQLUtil.closeQuietly(rs);
rs = null;
SQLUtil.closeQuietly(ps);
ps = null;
}
// Verify the account is enabled by function call
// add password param
List<SQLParam> params = new ArrayList<SQLParam>();
params.add(new SQLParam(USER_NAME, username.toUpperCase()));
params.add(new SQLParam("password", password));
final String sql = "select wavesetValidateFunc1(? , ?) from dual";
try {
ps = getConn().prepareCall(sql, params);
rs = ps.executeQuery();
if (rs == null || !rs.next()) {
// user name is wrong, no result
throw new InvalidCredentialException(getCfg().getMessage(MSG_AUTH_FAILED, username));
}
final boolean valid = (rs.getInt(1) == 1);
if (!valid) {
// password is wrong
throw new InvalidPasswordException(getCfg().getMessage(MSG_AUTH_FAILED, username));
}
} catch (Exception ex) {
LOG.error(ex, "autenticate exception");
SQLUtil.rollbackQuietly(getConn());
throw ConnectorException.wrap(ex);
} finally {
SQLUtil.closeQuietly(rs);
rs = null;
SQLUtil.closeQuietly(ps);
ps = null;
}
getConn().commit();
LOG.ok("authenticate user ''{0}'' done", username);
return uid;
}
/**
*
*/
private void createCheckValidateFunction() {
LOG.ok("createCheckValidateFunction");
StringBuilder b = new StringBuilder();
b.append("create or replace function wavesetValidateFunc1 (username IN varchar2, password IN varchar2) ");
b.append("RETURN NUMBER is ");
b.append("BEGIN ");
b.append("IF (" + getCfg().app()
+ "FND_USER_PKG.ValidateLogin(username, password) = TRUE ) THEN RETURN 1; ");
b.append("ELSE RETURN 0; ");
b.append("END IF; ");
b.append("END;");
// make sure the function exist
CallableStatement st = null;
try {
st = getConn().prepareCall(b.toString());
st.execute();
} catch (Exception ex) {
LOG.error(ex, b.toString());
throw ConnectorException.wrap(ex);
} finally {
SQLUtil.closeQuietly(st);
st = null;
}
}
/**
* {@inheritDoc}
*/
public Uid resolveUsername(ObjectClass objectClass, String username, OperationOptions options) {
LOG.ok("resolveUsername ''{0}''", username);
Assertions.nullCheck(objectClass, "objectClass");
Assertions.nullCheck(username, "username");
// call the validation function
PreparedStatement ps = null;
ResultSet rs = null;
final String sqlAccount =
"select user_name from " + getCfg().app() + "fnd_user where upper(user_name) = ?";
List<SQLParam> par1 = new ArrayList<SQLParam>();
par1.add(new SQLParam(USER_NAME, username.toUpperCase()));
final Uid uid = new Uid(username.toUpperCase());
try {
ps = getConn().prepareCall(sqlAccount, par1);
rs = ps.executeQuery();
if (rs == null || !rs.next()) {
// account not found
throw new InvalidCredentialException(getCfg().getMessage(MSG_AUTH_FAILED, username));
}
} catch (Exception ex) {
LOG.error(ex, "autenticate exception");
SQLUtil.rollbackQuietly(getConn());
throw ConnectorException.wrap(ex);
} finally {
SQLUtil.closeQuietly(rs);
rs = null;
SQLUtil.closeQuietly(ps);
ps = null;
}
getConn().commit();
LOG.ok("authenticate user ''{0}'' done", username);
return uid;
}
}