AuthenticatedCommand.java revision a29d50079096351c50b4dca5a885101c62b55e57
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2006 Sun Microsystems 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
* https://opensso.dev.java.net/public/CDDLv1.0.html or
* opensso/legal/CDDLv1.0.txt
* 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 opensso/legal/CDDLv1.0.txt.
* 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]"
*
* Portions Copyrighted 2011-2016 ForgeRock AS.
*/
package com.sun.identity.cli;
import static org.forgerock.openam.utils.CollectionUtils.asSet;
import com.iplanet.sso.SSOException;
import com.iplanet.sso.SSOToken;
import com.iplanet.sso.SSOTokenManager;
import com.sun.identity.security.DecodeAction;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.AccessController;
import java.text.MessageFormat;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
/**
* This is the base class for all commands that require a user to be
* authenticated in order to execute a command.
*/
public abstract class AuthenticatedCommand extends CLICommandBase {
private static final String FILE_REFERENCE_SUFFIX = "-file";
// One-off case of an existing properties that makes use of the -file suffix in an existing property
// => don't apply the file reference rule in this case.
private static final Set<String> FILE_REFERENCE_SUFFIX_EXEMPT =
asSet("iplanet-am-logging-num-hist-file", "iplanet-am-auth-windowsdesktopsso-keytab-file");
private String adminID;
private String adminPassword;
protected SSOToken ssoToken;
/**
* Authenticates the administrator. Dervived classes needs to
* call this method from the dervived method,
* <code>handleRequest(RequestContext rc)</code>.
* Override this method to get user name and passowrd.
*
* @param rc Request Context.
* @throws CLIException if authentication fails.
*/
@Override
public void handleRequest(RequestContext rc)
throws CLIException
{
super.handleRequest(rc);
ssoToken = rc.getCLIRequest().getSSOToken();
if (ssoToken == null) {
adminID = getStringOptionValue(
AccessManagerConstants.ARGUMENT_ADMIN_ID);
adminPassword = getPassword();
}
}
private String getPassword()
throws CLIException
{
String fileName = getStringOptionValue(
AccessManagerConstants.ARGUMENT_PASSWORD_FILE);
String password = CLIUtil.getFileContent(getCommandManager(),
fileName, true);
String decodedPwd = (String) AccessController.doPrivileged(
new DecodeAction(password));
if (decodedPwd != null) {
password = decodedPwd;
}
validatePwdFilePermissions(fileName);
return password;
}
private void validatePwdFilePermissions(String fileName)
throws CLIException {
if (System.getProperty("path.separator").equals(":")) {
try {
String[] parameter = {"/bin/ls", "-l", fileName};
Process p = Runtime.getRuntime().exec(parameter);
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
String s = stdInput.readLine();
if (s != null) {
int idx = s.indexOf(" ");
if (idx != -1) {
String permission = s.substring(0, idx);
if (!permission.startsWith("-r--------")) {
String msg = getCommandManager().getResourceBundle()
.getString(
"error-message-password-file-not-readonly");
Object[] param = {fileName};
throw new CLIException(MessageFormat.format(
msg, param),
ExitCodes.REQUEST_CANNOT_BE_PROCESSED);
}
}
}
} catch (IOException e) {
//ignore, this should not happen because we are able to
// read the file in getPassword method.
}
}
}
protected String getAdminPassword() {
return adminPassword;
}
protected String getAdminID() {
return adminID;
}
protected SSOToken getAdminSSOToken() {
return ssoToken;
}
protected void ldapLogin()
throws CLIException
{
if (ssoToken == null) {
Authenticator auth = Authenticator.getInstance();
String bindUser = getAdminID();
ssoToken = auth.ldapLogin(getCommandManager(), bindUser,
getAdminPassword());
} else {
try {
SSOTokenManager mgr = SSOTokenManager.getInstance();
mgr.validateToken(ssoToken);
} catch (SSOException e) {
throw new CLIException(e, ExitCodes.SESSION_EXPIRED);
}
}
}
@Override
protected void writeLog(
int type,
Level level,
String msgid,
String[] msgdata
) throws CLIException {
CommandManager mgr = getCommandManager();
LogWriter.log(mgr, type, level, msgid, msgdata,getAdminSSOToken());
}
/**
* Post-process any attributes specified for the module instance (either via data file or on the command line) to
* resolve any file references. Any attribute can be specified using a -file suffix on the attribute name. This
* will cause the value to be treated as a file name, and the associated file to be read in (in the platform
* default encoding) and used as the attribute value. The attribute will be renamed to remove the -file suffix
* during this process.
*
* @param attrs the raw attributes read from the command line and/or data file.
* @return the processed attributes with all file references resolved.
* @throws CLIException if a referenced file cannot be read or if an attribute is specified both normally and using
* a -file reference.
*/
protected Map<String, Set<String>> processFileAttributes(Map<String, Set<String>> attrs) throws CLIException {
Map<String, Set<String>> result = attrs;
if (attrs != null) {
result = new LinkedHashMap<>(attrs.size());
for (Map.Entry<String, Set<String>> attr : attrs.entrySet()) {
String key = attr.getKey();
Set<String> values = attr.getValue();
if (key != null && key.endsWith(FILE_REFERENCE_SUFFIX) && !FILE_REFERENCE_SUFFIX_EXEMPT.contains(key)) {
key = key.substring(0, key.length() - FILE_REFERENCE_SUFFIX.length());
if (attrs.containsKey(key)) {
throw new CLIException("Cannot specify both normal and " + FILE_REFERENCE_SUFFIX
+ " attribute: " + key, ExitCodes.DUPLICATED_OPTION);
}
if (values != null) {
Set<String> newValues = new LinkedHashSet<String>(values.size());
for (String value : values) {
newValues.add(CLIUtil.getFileContent(getCommandManager(), value));
}
values = newValues;
}
}
result.put(key, values);
}
}
return result;
}
}