/**
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2005 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]"
*
* $Id: AMModuleProperties.java,v 1.8 2009/05/02 22:11:28 kevinserwin Exp $
*
*/
/*
* Portions Copyrighted 2011-16 ForgeRock AS
*/
package com.sun.identity.authentication.spi;
import com.sun.identity.authentication.callbacks.HiddenValueCallback;
import com.sun.identity.authentication.callbacks.ScriptTextOutputCallback;
import com.sun.identity.authentication.service.AuthD;
import com.sun.identity.authentication.share.AuthXMLTags;
import com.sun.identity.shared.debug.Debug;
import com.sun.identity.shared.xml.XMLUtils;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.ChoiceCallback;
import javax.security.auth.callback.ConfirmationCallback;
import javax.security.auth.callback.LanguageCallback;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.TextInputCallback;
import javax.security.auth.callback.TextOutputCallback;
import javax.servlet.ServletContext;
import javax.xml.parsers.DocumentBuilder;
import org.forgerock.openam.authentication.callbacks.PollingWaitCallback;
import org.forgerock.openam.utils.CollectionUtils;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
class AMModuleProperties {
private String moduleName;
private String order;
private int p = 0; // callback of the specific pages
private List page = new ArrayList();
private List attribute; // Attribute for each page
private List require; // isRequire for each page
private List<String> infoText;
private Hashtable rtable = new Hashtable();
private Callback[] callbacks = null;
private static Map moduleProps = new HashMap();
private static final String amAuth = "amAuth";
private static Debug debug = Debug.getInstance(amAuth);
AMModuleProperties(
String fileName,
ServletContext servletContext
) throws AuthLoginException {
InputStream in = null;
try {
DocumentBuilder builder = XMLUtils.getSafeDocumentBuilder(false);
if (servletContext != null) {
in = servletContext.getResourceAsStream(fileName);
}
if (in == null) {
in = Thread.currentThread().getContextClassLoader()
.getResourceAsStream(fileName.substring(1));
// remove leading '/' from fileName
}
Document doc = builder.parse(in);
in.close();
walk(doc);
for(int i=1; i<=rtable.size(); i++) {
Callback[] cb = (Callback[]) rtable.get(Integer.toString(i));
page.add(cb);
}
} catch(Exception e) {
debug.error("AMModuleProperties, parse file :" +fileName);
debug.error("AMModuleProperties, parser error :" , e);
throw new AuthLoginException(amAuth, "getModulePropertiesError",
null);
} finally {
try {
in.close();
} catch (Exception ee) {
}
}
}
/**
* Return the list of page
* @return <code>List</code> of page
*/
private List getCallbacks() {
return page;
}
/**
* Return the list of authentication module property
* @param fileName that has module properties
* @return <code>List</code> of module property
* @exception AuthLoginException if fails to get properties from the file.
*/
public static List getModuleProperties(String fileName) throws AuthLoginException {
List propertiesList = (List) moduleProps.get(fileName);
if (propertiesList != null) {
return propertiesList;
}
ServletContext servletContext = AuthD.getAuth().getServletContext();
InputStream resStream = null;
try {
if (servletContext != null) {
resStream = servletContext.getResourceAsStream(fileName);
}
if (resStream == null) {
// remove leading '/' from fileName
resStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName.substring(1));
}
// file might be empty for modules like Cert,Anonymous etc.
if (resStream != null && resStream.read() == -1) {
if (debug.messageEnabled()) {
debug.message(fileName + " is empty");
}
propertiesList = new ArrayList();
synchronized(moduleProps) {
moduleProps.put(fileName, propertiesList);
}
return propertiesList;
}
} catch (Exception e) {
debug.message("getModuleProperties: Error: " ,e);
} finally {
try {
resStream.close();
} catch (Exception ee) {
debug.message("Error closing input stream");
}
}
AMModuleProperties prop = new AMModuleProperties(fileName,
servletContext);
propertiesList = prop.getCallbacks();
if (CollectionUtils.isEmpty(propertiesList)) {
synchronized(moduleProps) {
moduleProps.put(fileName, propertiesList);
}
}
return propertiesList;
}
//walk the DOM tree and create the callback array
private void walk(Node node)
{
int type = node.getNodeType();
String nodeName = node.getNodeName();
debug.message("Callback type: " + nodeName);
String tmp;
Node sub;
switch(type)
{
case Node.ELEMENT_NODE:
{
if (nodeName.equals("ModuleProperties")) {
moduleName = getAttribute(node, "moduleName");
} else if (nodeName.equals("Callbacks")) {
p = 0;
String timeout = getAttribute(node, "timeout");
String template = getAttribute(node, "template");
if(template == null){
template = "";
}
String image = getAttribute(node, "image");
if(image == null){
image = "";
}
String header = getAttribute(node, "header");
boolean error = Boolean.valueOf(
getAttribute(node, "error")).booleanValue();
int size = Integer.parseInt(getAttribute(node, "length")) + 1;
int t=0;
if (timeout!=null) {
t = Integer.parseInt(timeout);
}
order = getAttribute(node, "order");
callbacks = new Callback[size];
callbacks[p] = new PagePropertiesCallback(moduleName,
header, image, t, template, error, order);
p++;
attribute = new ArrayList();
require = new ArrayList();
infoText = new ArrayList<String>();
} else if (nodeName.equals("NameCallback")) {
sub = node.getFirstChild();
sub = sub.getNextSibling();
String prompt = sub.getFirstChild().getNodeValue();
String dftName = null;
sub = sub.getNextSibling().getNextSibling();
if (sub != null) {
sub = sub.getFirstChild();
dftName = sub.getNodeValue();
callbacks[p] = new NameCallback(prompt, dftName);
} else {
callbacks[p] = new NameCallback(prompt);
}
tmp = getAttribute(node, "isRequired");
if (tmp != null) {
if (tmp.equals("true")) {
require.add("true");
} else {
require.add("");
}
} else {
require.add("");
}
tmp = getAttribute(node, "attribute");
if (tmp!=null) {
attribute.add(tmp);
} else {
attribute.add("");
}
tmp = getAttribute(node, "infoText");
if (tmp!=null) {
infoText.add(tmp);
} else {
infoText.add("");
}
p++;
} else if (nodeName.equals("HiddenValueCallback")) {
sub = node.getFirstChild();
sub = sub.getNextSibling();
String id = sub.getFirstChild().getNodeValue();
String dftName = null;
sub = sub.getNextSibling().getNextSibling();
if (sub != null) {
sub = sub.getFirstChild();
dftName = sub.getNodeValue();
callbacks[p] = new HiddenValueCallback(id, dftName);
} else {
callbacks[p] = new HiddenValueCallback(id);
}
tmp = getAttribute(node, "isRequired");
if (Boolean.parseBoolean(tmp)) {
require.add("true");
} else {
require.add("");
}
tmp = getAttribute(node, "attribute");
if (tmp != null) {
attribute.add(tmp);
} else {
attribute.add("");
}
tmp = getAttribute(node, "infoText");
if (tmp != null) {
infoText.add(tmp);
} else {
infoText.add("");
}
p++;
} else if (nodeName.equals("PasswordCallback")) {
String echo = getAttribute(node, "echoPassword");
sub = node.getFirstChild();
sub = sub.getNextSibling().getFirstChild();
String prompt = sub.getNodeValue();
boolean b = Boolean.valueOf(echo).booleanValue();
callbacks[p] = new PasswordCallback(prompt, b);
tmp = getAttribute(node, "isRequired");
if (tmp!=null) {
if (tmp.equals("true")) {
require.add("true");
} else {
require.add("");
}
} else {
require.add("");
}
tmp = getAttribute(node, "attribute");
if (tmp!=null) {
attribute.add(tmp);
} else {
attribute.add("");
}
tmp = getAttribute(node, "infoText");
if (tmp!=null) {
infoText.add(tmp);
} else {
infoText.add("");
}
p++;
} else if (nodeName.equals("ChoiceCallback")) {
String multiple = getAttribute(
node, "multipleSelectionsAllowed");
String prompt=null;
String[] choices=null;
int defaultChoice=0;
boolean mch = Boolean.valueOf(multiple).booleanValue();
for (sub=node.getFirstChild(); sub!=null;
sub=sub.getNextSibling()
) {
if (sub.getNodeName().equals("Prompt")) {
prompt = sub.getFirstChild().getNodeValue();
} else if (sub.getNodeName().equals("ChoiceValues")
) {
int len = 0;
Node ss = sub.getFirstChild().getNextSibling();
for (Node count=ss; count!=null;
count=count.getNextSibling()
.getNextSibling()
) {
len++;
}
choices = new String[len];
for(int i=0; i<len; i++) {
choices[i] = ss.getFirstChild().
getNextSibling().getFirstChild().
getNodeValue();
if (Boolean.valueOf(getAttribute(ss,
"isDefault")).booleanValue()
) {
defaultChoice = i;
}
ss = ss.getNextSibling().getNextSibling();
}
break;
}
}
callbacks[p] = new ChoiceCallback(
prompt, choices, defaultChoice, mch);
tmp = getAttribute(node, "isRequired");
if (tmp!=null) {
if (tmp.equals("true")) {
require.add("true");
} else {
require.add("");
}
} else {
require.add("");
}
tmp = getAttribute(node, "attribute");
if (tmp!=null) {
attribute.add(tmp);
} else {
attribute.add("");
}
tmp = getAttribute(node, "infoText");
if (tmp!=null) {
infoText.add(tmp);
} else {
infoText.add("");
}
p++;
} else if (nodeName.equals("ConfirmationCallback")) {
int messageType = ConfirmationCallback.INFORMATION;
int defaultOption = 0;
String[] options = null;
for (sub=node.getFirstChild(); sub!=null;
sub=sub.getNextSibling()
) {
if (sub.getNodeName().equals("OptionValues")) {
int len = 0;
Node ss = sub.getFirstChild().getNextSibling();
for (Node count=ss; count!=null;
count=count.getNextSibling()
.getNextSibling()
) {
len++;
}
options = new String[len];
for(int i=0; i<len; i++) {
options[i] = ss.getFirstChild()
.getNextSibling().getFirstChild().
getNodeValue();
ss = ss.getNextSibling().getNextSibling();
}
break;
}
}
callbacks[p] = new ConfirmationCallback(
messageType, options, defaultOption);
p++;
} else if (nodeName.equals("TextInputCallback")) {
sub = node.getFirstChild();
sub = sub.getNextSibling().getFirstChild();
String prompt = sub.getNodeValue();
callbacks[p] = new TextInputCallback(prompt);
p++;
} else if (nodeName.equals("TextOutputCallback")) {
int messageType = TextOutputCallback.ERROR;
String s = getAttribute(node, "messageType");
String value = node.getFirstChild().getNodeValue();
if (s.equals("script")) {
callbacks[p] = new ScriptTextOutputCallback(value);
} else {
if (s.equals("error")) {
messageType = TextOutputCallback.ERROR;
} else if (s.equals("warning")) {
messageType = TextOutputCallback.WARNING;
} else { //default to information
messageType = TextOutputCallback.INFORMATION;
}
callbacks[p] = new TextOutputCallback(messageType, value);
}
p++;
} else if (nodeName.equals("LanguageCallback")) {
for (sub = node.getFirstChild(); sub != null; sub = sub.getNextSibling()) {
if (sub.getNodeName().equals("ChoiceValue")) {
String isdefault = getAttribute(
sub, "isDefault");
}
}
callbacks[p] = new LanguageCallback();
p++;
} else if (PollingWaitCallback.NODE_NAME.equals(nodeName)) {
callbacks[p++] = PollingWaitCallback.makeCallback()
.withWaitTime(getAttribute(node, "waitTime"))
.build();
} else if (nodeName.equals(AuthXMLTags.HTTP_CALLBACK)) {
String header = null;
String negotiation = null;
String code = null;
sub = node.getFirstChild();
for (; sub!=null; sub=sub.getNextSibling()) {
String tmpStr = sub.getNodeName();
if (tmpStr.equals(AuthXMLTags.HTTP_HEADER)) {
header = sub.getFirstChild().getNodeValue();
} else if (tmpStr.equals(AuthXMLTags.HTTP_NEGO)) {
negotiation= sub.getFirstChild().getNodeValue();
} else if (tmpStr.equals(AuthXMLTags.HTTP_CODE)) {
code = sub.getFirstChild().getNodeValue();
}
}
callbacks[p]= new HttpCallback(header,negotiation,code);
p++;
} else if (nodeName.equals(AuthXMLTags.REDIRECT_CALLBACK)) {
String redirectUrl = null;
String statusParameter = null;
String redirectBackUrlCookie = null;
Map redirectData = new HashMap();
String method =
getAttribute(node, AuthXMLTags.REDIRECT_METHOD);
sub = node.getFirstChild();
for (; sub!=null; sub=sub.getNextSibling()) {
String tmpStr = sub.getNodeName();
if (tmpStr.equals(AuthXMLTags.REDIRECT_URL)) {
redirectUrl =
sub.getFirstChild().getNodeValue();
} else if (tmpStr.equals(
AuthXMLTags.REDIRECT_STATUS_PARAM)) {
statusParameter =
sub.getFirstChild().getNodeValue();
} else if (tmpStr.equals(
AuthXMLTags.REDIRECT_BACK_URL_COOKIE)) {
redirectBackUrlCookie =
sub.getFirstChild().getNodeValue();
} else if (tmpStr.equals(
AuthXMLTags.REDIRECT_DATA)) {
String name = null;
String value = null;
Node ss = sub.getFirstChild().getNextSibling();
String tmpStrName = ss.getNodeName();
if (tmpStrName.equals("Name")) {
name = ss.getFirstChild().getNodeValue();
}
ss = ss.getNextSibling().getNextSibling();
String tmpStrValue = ss.getNodeName();
if (tmpStrValue.equals("Value")) {
value = ss.getFirstChild().getNodeValue();
}
redirectData.put(name,value);
}
}
if (debug.messageEnabled()) {
debug.message("redirectUrl : " + redirectUrl);
debug.message("statusParameter : "
+ statusParameter);
debug.message("redirectBackUrlCookie : "
+ redirectBackUrlCookie);
debug.message("redirectData : " + redirectData);
debug.message("method : " + method);
}
callbacks[p]= new RedirectCallback(redirectUrl, redirectData, method);
p++;
}
break;
}//end of element
default:
break;
}//end of switch
//recurse
for (Node child = node.getFirstChild(); child != null;
child = child.getNextSibling()
) {
walk(child);
}
//without this the ending tags will miss
if ( type == Node.ELEMENT_NODE )
{
if (nodeName.equals("Callbacks")) {
((PagePropertiesCallback) callbacks[0]).setAttribute(attribute);
((PagePropertiesCallback) callbacks[0]).setRequire(require);
((PagePropertiesCallback) callbacks[0]).setInfoText(infoText);
rtable.put(order, callbacks);
//attrtable.put(order, subAttr);
//requiretable.put(order, subRequire);
}
}
}//end of walk
private String getAttribute(Node node, String name) {
NamedNodeMap nnm = node.getAttributes();
if(nnm != null ) {
int len = nnm.getLength() ;
Attr attr;
for ( int i = 0; i < len; i++ ) {
attr = (Attr)nnm.item(i);
if (attr.getNodeName().equals(name)) {
return attr.getNodeValue();
}
}
}
return null;
}
}