/*******************************************************************************
* Copyright (c) 2006-2010 eBay Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*******************************************************************************/
package org.ebayopensource.turmeric.policyservice.provider;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.ebayopensource.turmeric.runtime.common.impl.utils.LogManager;
import org.ebayopensource.turmeric.utils.DomParseUtils;
import org.ebayopensource.turmeric.utils.config.exceptions.PolicyProviderException;
import org.ebayopensource.turmeric.utils.config.impl.BaseFilePolicyProvider;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
* AuthenticationFilePolicyProvider
*
* A policy provider that parses policy given the XML configuration and its
* corresponding schema XSD
*
* Code derived from EBay reference codes.
*/
public class AuthenticationFilePolicyProvider extends BaseFilePolicyProvider implements AuthenticationPolicyProvider {
private static Logger s_logger = LogManager.getInstance(AuthenticationFilePolicyProvider.class);
private static final String RELATIVE_CONFIG_PATH = "META-INF/security/config";
private static final String RELATIVE_SCHEMA_PATH = "META-INF/security/schema";
private static final String AUTHN_POLICY_FILENAME = "AuthenticationPolicy.xml";
private static final String AUTHN_POLICY_SCHEMA = "AuthenticationPolicy.xsd";
private static final String POLICY_ROOT_ELEMENT = "authentication-policy";
private static final String ALL_OP = "*";
private String policyFile;
private String policySchema;
private String policyRootElement;
private Map<Resource, OperationHolder> m_operationHolderMap;
/**
* Instantiates a new authentication file policy provider.
*/
public AuthenticationFilePolicyProvider() {
this(AUTHN_POLICY_FILENAME, AUTHN_POLICY_SCHEMA, POLICY_ROOT_ELEMENT);
}
/**
* Instantiates a new authentication file policy provider.
*
* @param policyFile
* the policy file
* @param policySchema
* the policy schema
* @param policyRootElement
* the policy root element
*/
AuthenticationFilePolicyProvider(String policyFile, String policySchema, String policyRootElement) {
super();
this.policyFile = policyFile;
this.policySchema = policySchema;
this.policyRootElement = policyRootElement;
}
/* (non-Javadoc)
* @see org.ebayopensource.turmeric.utils.config.impl.BaseFilePolicyProvider#getPolicyFileName()
*/
@Override
public String getPolicyFileName() {
return RELATIVE_CONFIG_PATH + "/" + policyFile;
}
/* (non-Javadoc)
* @see org.ebayopensource.turmeric.utils.config.impl.BaseFilePolicyProvider#getPolicySchemaName()
*/
@Override
public String getPolicySchemaName() {
return RELATIVE_SCHEMA_PATH + "/" + policySchema;
}
/* (non-Javadoc)
* @see org.ebayopensource.turmeric.utils.config.impl.BaseFilePolicyProvider#getPolicyRootElement()
*/
@Override
public String getPolicyRootElement() {
return policyRootElement;
}
/* (non-Javadoc)
* @see org.ebayopensource.turmeric.utils.config.impl.BaseFilePolicyProvider#mapPolicyData(org.w3c.dom.Element)
*/
@Override
protected void mapPolicyData(Element policyData) throws PolicyProviderException {
m_operationHolderMap = new HashMap<Resource, OperationHolder>();
m_operationHolderMap.clear();
if (policyData == null) {
s_logger.log(Level.SEVERE, "AuthenticationFilePolicyProvider mapPolicyData(): Authn policy data is empty!!!");
return;
}
try {
// iterate thru the resource list
NodeList resourceList = DomParseUtils.getImmediateChildrenByTagName(policyData, "resource");
for (int i = 0; i < resourceList.getLength(); i++) {
Element resource = (Element) resourceList.item(i);
String resourceName = DomParseUtils.getRequiredAttribute(getPolicyFileName(), resource, "name");
String resourceType = DomParseUtils.getRequiredAttribute(getPolicyFileName(), resource, "type");
String defaultAuthenticationMethod = DomParseUtils.getRequiredAttribute(getPolicyFileName(), resource, "default-authentication-method");
if (defaultAuthenticationMethod != null) {
// TODO - verify why need to convert to lower case
defaultAuthenticationMethod = defaultAuthenticationMethod.toLowerCase();
}
// TODO - verify why need to convert to upper case
Resource resourceObj = new Resource(resourceType.toUpperCase(), resourceName);
OperationHolder operationHolder = new OperationHolder(defaultAuthenticationMethod);
m_operationHolderMap.put(resourceObj, operationHolder);
NodeList opList = DomParseUtils.getImmediateChildrenByTagName(resource, "operation");
// iterate thru the operation list
for (int j = 0; j < opList.getLength(); j++) {
Element operation = (Element) opList.item(j);
String operationName = DomParseUtils.getRequiredAttribute(getPolicyFileName(), operation, "name");
NodeList authnMethodList = DomParseUtils.getImmediateChildrenByTagName(operation, "authentication-method");
List<String> authenticationMethods = new ArrayList<String>();
for (int k = 0; k < authnMethodList.getLength(); k++) {
Element authnMethodElem = (Element) authnMethodList.item(k);
String authnMethod = authnMethodElem.getFirstChild().getNodeValue();
if (authnMethod != null) {
authnMethod = authnMethod.toLowerCase();
authenticationMethods.add(authnMethod);
}
}
// add operation (key) and authentication methods (value) to operation holder
operationHolder.addAuthenticationMethods(operationName, authenticationMethods);
}
}
} catch(Exception e) {
s_logger.log(Level.SEVERE, "exception", e);
throw new PolicyProviderException(
"Error in mapping authn file policy: " + e.getMessage(),
e);
}
}
/**
* Return the authentication policy associated to this resource/operation.
*
* @param resourceName
* the resource name
* @param operationName
* the operation name
* @param resourceType
* the resource type
* @return the authn policy by resource
* @throws PolicyProviderException
* the policy provider exception
*/
public AuthenticationProviderInfo getAuthnPolicyByResource(String resourceName, String operationName, String resourceType) throws PolicyProviderException {
List<String> emptyAuthMethods = Collections.emptyList();
AuthenticationProviderInfo resourceAuthInfo = new AuthenticationProviderInfo();
resourceAuthInfo.setResourceName(resourceName);
resourceAuthInfo.setResourceType(resourceType);
resourceAuthInfo.setOperationName(operationName);
resourceAuthInfo.setAuthenticationMethods(emptyAuthMethods);
if (resourceName == null ||
operationName == null ||
resourceType == null ||
resourceName.equals("") ||
operationName.equals("") ||
resourceType.equals("")) {
return resourceAuthInfo;
}
// TODO - verify why need to convert to upper case
Resource resource = new Resource(resourceType.toUpperCase(), resourceName);
OperationHolder opHolder = m_operationHolderMap.get(resource);
if (opHolder == null) {
return resourceAuthInfo;
}
if (opHolder.getDefaultAuthenticationMethod() == null) {
String errorMsg = "Policy data error: Authentication method not defined for resource " + resource.getName() +
", type " + resource.getType() + ", and operation " + operationName;
throw new PolicyProviderException(
errorMsg);
}
List<String> defaultAuthenticationMethods = new ArrayList<String>();
defaultAuthenticationMethods.add(opHolder.getDefaultAuthenticationMethod());
List<String> authenticationMethods = opHolder.getAuthenticationMethods(operationName);
if (authenticationMethods == null || authenticationMethods.isEmpty()) {
// check for "*" if no matching authentication methods returned for this operation
// otherwise use the default authentication method
authenticationMethods = opHolder.getAuthenticationMethods(ALL_OP);
if (authenticationMethods != null) {
resourceAuthInfo.setAuthenticationMethods(authenticationMethods);
} else {
resourceAuthInfo.setAuthenticationMethods(defaultAuthenticationMethods);
}
} else {
// use authentication methods returned for this operation
resourceAuthInfo.setAuthenticationMethods(authenticationMethods);
}
return resourceAuthInfo;
}
/**
* The logic of this class was copied from Resource class in reference/PolicyServiceProviderImpl.
*
*/
private static class Resource {
private String m_type;
private String m_name;
public Resource(String type, String name) {
m_type = type;
m_name = name;
}
public String getType() {
return m_type;
}
public String getName() {
return m_name;
}
@Override
public int hashCode() {
final int PRIME = 31;
int result = 1;
result = PRIME * result + ((m_name == null) ? 0 : m_name.hashCode());
result = PRIME * result + ((m_type == null) ? 0 : m_type.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Resource other = (Resource) obj;
if (m_name == null) {
if (other.m_name != null) {
return false;
}
} else if (!m_name.equals(other.m_name)) {
return false;
}
if (m_type == null) {
if (other.m_type != null) {
return false;
}
} else if (!m_type.equals(other.m_type)) {
return false;
}
return true;
}
@Override
public String toString() {
StringBuilder buffer = new StringBuilder();
buffer.append("type {").append(m_type).append("}");
buffer.append(" name {").append(m_name).append("}");
return buffer.toString();
}
}
/**
* The logic of this class was copied from AuthnPolicyOperationHolder class in reference/PolicyServiceProviderImpl.
*
*/
private static class OperationHolder {
// map of operation name (key) and authenticated methods (value)
private Map<String, List<String>> m_authenticationMethods;
private String m_defaultAuthenticationMethod;
public OperationHolder(String defaultAuthenticationMethod) {
m_authenticationMethods = new HashMap<String, List<String>>();
this.m_defaultAuthenticationMethod = defaultAuthenticationMethod;
}
public List<String> getAuthenticationMethods(String operationName) {
return m_authenticationMethods.get(operationName);
}
public String getDefaultAuthenticationMethod() {
return m_defaultAuthenticationMethod;
}
public void addAuthenticationMethods(String operationName, List<String> authenticationMethods) {
m_authenticationMethods.put(operationName, authenticationMethods);
}
@Override
public String toString() {
StringBuilder buffer = new StringBuilder();
buffer.append("default authentication method {").append(m_defaultAuthenticationMethod).append("}");
if (m_authenticationMethods != null && m_authenticationMethods.size() > 0) {
Iterator<String> keyIter = m_authenticationMethods.keySet().iterator();
while (keyIter.hasNext()) {
String key = keyIter.next();
buffer.append(" operation {").append(key).append("}");
List<String> authMethods = m_authenticationMethods.get(key);
if (authMethods != null && authMethods.size() > 0) {
for (String authMethod : authMethods) {
buffer.append(" authentication method {").append(authMethod).append("}");
}
}
}
}
return buffer.toString();
}
}
}