package eu.dnetlib.enabling.aas.client;

import java.util.ArrayList;
import java.util.List;

import org.opensaml.lite.saml2.core.Assertion;
import org.opensaml.lite.xacml.XACMLConstants;

import eu.dnetlib.enabling.aas.DNetAuthenticateRequest;
import eu.dnetlib.enabling.aas.xacml.ctx.ActionType;
import eu.dnetlib.enabling.aas.xacml.ctx.AttributeType;
import eu.dnetlib.enabling.aas.xacml.ctx.AttributeValueType;
import eu.dnetlib.enabling.aas.xacml.ctx.EnvironmentType;
import eu.dnetlib.enabling.aas.xacml.ctx.RequestType;
import eu.dnetlib.enabling.aas.xacml.ctx.ResourceType;
import eu.dnetlib.enabling.aas.xacml.ctx.SubjectType;
import eu.dnetlib.enabling.aas.xacml.profile.saml.XACMLAuthzDecisionQueryType;


/**
 * Client security service helper class.
 * @author mhorst
 *
 */
public abstract class ClientSecurityServiceHelper {

	public static final String AUTHN_TYPE_USER = "user";
	
//	public static final String AUTHN_TYPE_PROCESS = "process";
	
	
	/**
	 * Builds {@link AuthenticateRequest} object for logging in user.
	 * @param login
	 * @param password
	 * @param ipAddress
	 * @param authnType authentication type
	 * @param backwardCompatibility backward compatible with previous version of AAS (rev. 10xxx)
	 * @return {@link AuthenticateRequest} object for logging in user
	 */
	public static DNetAuthenticateRequest buildUserAuthnRequest(String login, 
			String password, String ipAddress, String authnType, boolean backwardCompatiblity) {
		XACMLAuthzDecisionQueryType authnQuery = new XACMLAuthzDecisionQueryType();
		DNetAuthenticateRequest request = new DNetAuthenticateRequest(authnQuery);
		RequestType samlRequest = new RequestType();
		authnQuery.setRequest(samlRequest);
		
		List<SubjectType> subjects = new ArrayList<SubjectType>();
		SubjectType samlSubject = new SubjectType();
		samlSubject.setSubjectCategory(XACMLConstants.ACCESS_SUBJECT_CATEGORY);
		AttributeType subjectAttr1 = new AttributeType();
		subjectAttr1.setAttributeID(XACMLConstants.SUBJECT_ID);
		subjectAttr1.setDataType(XACMLConstants.DATATYPE_STRING);
		AttributeValueType subjectAttr1Value = new AttributeValueType();
		subjectAttr1Value.setValue(authnType);
		subjectAttr1.setAttributeValues(new AttributeValueType[] {subjectAttr1Value});
		samlSubject.setAttributes(new AttributeType[] {subjectAttr1});
		
		SubjectType samlSubject2 = new SubjectType();
		samlSubject2.setSubjectCategory(XACMLConstants.PASS_SUBJECT_CATEGORY);
		AttributeType subjectAttr2 = new AttributeType();
		subjectAttr2.setAttributeID(XACMLConstants.PASS_ATTR_ID);
		subjectAttr2.setDataType(XACMLConstants.DATATYPE_STRING);
		AttributeValueType subjectAttr2Value = new AttributeValueType();
		subjectAttr2Value.setValue(password);
		subjectAttr2.setAttributeValues(new AttributeValueType[] {subjectAttr2Value});
		samlSubject2.setAttributes(new AttributeType[] {subjectAttr2});
		
		SubjectType samlSubject3 = new SubjectType();
		samlSubject3.setSubjectCategory(XACMLConstants.SUBJECT_PARAM_CATEGORY);
		AttributeType subjectAttr3 = new AttributeType();
		subjectAttr3.setAttributeID(XACMLConstants.SUBJECT_PARAM_ID);
		subjectAttr3.setDataType(XACMLConstants.DATATYPE_STRING);
		AttributeValueType subjectAttr3Value = new AttributeValueType();
		subjectAttr3Value.setValue(login);
		subjectAttr3.setAttributeValues(new AttributeValueType[] {subjectAttr3Value});
		samlSubject3.setAttributes(new AttributeType[] {subjectAttr3});
		
		if (backwardCompatiblity) {
			SubjectType samlSubject3b = new SubjectType();
			samlSubject3b.setSubjectCategory(XACMLConstants.SUBJECT_PARAM_CATEGORY_OLD);
			AttributeType subjectAttr3b = new AttributeType();
			subjectAttr3b.setAttributeID(XACMLConstants.SUBJECT_PARAM_ID_OLD);
			subjectAttr3b.setDataType(XACMLConstants.DATATYPE_STRING);
			AttributeValueType subjectAttr3bValue = new AttributeValueType();
			subjectAttr3bValue.setValue(login);
			subjectAttr3b.setAttributeValues(new AttributeValueType[] {subjectAttr3bValue});
			samlSubject3b.setAttributes(new AttributeType[] {subjectAttr3b});
			subjects.add(samlSubject3b);
		}

		subjects.add(samlSubject);
		subjects.add(samlSubject2);
		subjects.add(samlSubject3);
        if (ipAddress != null) {
            SubjectType samlSubject4 = new SubjectType();
            samlSubject4.setSubjectCategory(
                    "urn:oasis:names:tc:xacml:1.0:subject-category:auxiliary");
            AttributeType subjectAttr4 = new AttributeType();
            subjectAttr4.setAttributeID(
                    "urn:oasis:names:tc:xacml:1.0:subject:ip-address");
            subjectAttr4.setDataType(XACMLConstants.DATATYPE_STRING);
            AttributeValueType subjectAttr4Value =
                    new AttributeValueType();
            subjectAttr4Value.setValue(ipAddress);
            subjectAttr4.setAttributeValues(new AttributeValueType[] {subjectAttr4Value});
            samlSubject4.setAttributes(new AttributeType[] {subjectAttr4});
            subjects.add(samlSubject4);
        }
        samlRequest.setSubjects(subjects.toArray(new SubjectType[subjects.size()]));
//		empty resource
		samlRequest.setResources(new ResourceType[] {new ResourceType()});
//		authenticate action (not required)
		ActionType samlAction = new ActionType();
		AttributeType actionAttr = new AttributeType();
		actionAttr.setAttributeID(XACMLConstants.ACTION_ID);
		actionAttr.setDataType(XACMLConstants.DATATYPE_STRING);
		AttributeValueType actionAttrValue = new AttributeValueType();
		actionAttrValue.setValue("authenticate");
		actionAttr.setAttributeValues(new AttributeValueType[] {actionAttrValue});
		samlAction.setAttributes(new AttributeType[] {actionAttr});
		samlRequest.setAction(samlAction);
//		environment
		EnvironmentType samlEnvironment = new EnvironmentType();
		samlRequest.setEnvironment(samlEnvironment);
		return request;
	}
	
	/**
	 * Builds {@link DNetAuthenticateRequest} object for sudoing user.
	 * Doesn't handle assertion attachment to the outgoing request 
	 * which has to be maintained separatelly. 
	 * @param login target user login
	 * @param ipAddress ip address from which user is logged in
	 * @param assertion {@link Assertion} belonging to sudoer 
	 * @return {@link DNetAuthenticateRequest} object
	 */
	public static DNetAuthenticateRequest buildSudoAuthnRequest(String login, 
			String ipAddress) {
		XACMLAuthzDecisionQueryType authnQuery = new XACMLAuthzDecisionQueryType();
		DNetAuthenticateRequest request = new DNetAuthenticateRequest(authnQuery);

		RequestType samlRequest = new RequestType();
		authnQuery.setRequest(samlRequest);
		
		List<SubjectType> subjects = new ArrayList<SubjectType>();
		SubjectType samlSubject = new SubjectType();
		samlSubject.setSubjectCategory(XACMLConstants.ACCESS_SUBJECT_CATEGORY);
		AttributeType subjectAttr1 = new AttributeType();
		subjectAttr1.setAttributeID(XACMLConstants.SUBJECT_ID);
		subjectAttr1.setDataType(XACMLConstants.DATATYPE_STRING);
		AttributeValueType subjectAttr1Value = new AttributeValueType();
		subjectAttr1Value.setValue(AUTHN_TYPE_USER);
		subjectAttr1.setAttributeValues(new AttributeValueType[] {subjectAttr1Value});
		samlSubject.setAttributes(new AttributeType[] {subjectAttr1});
		
		SubjectType samlSubject3 = new SubjectType();
		samlSubject3.setSubjectCategory(XACMLConstants.SUBJECT_PARAM_CATEGORY);
		AttributeType subjectAttr3 = new AttributeType();
		subjectAttr3.setAttributeID(XACMLConstants.SUBJECT_PARAM_ID);
		subjectAttr3.setDataType(XACMLConstants.DATATYPE_STRING);
		AttributeValueType subjectAttr3Value = new AttributeValueType();
		subjectAttr3Value.setValue(login);
		subjectAttr3.setAttributeValues(new AttributeValueType[] {subjectAttr3Value});
		samlSubject3.setAttributes(new AttributeType[] {subjectAttr3});

		subjects.add(samlSubject);
		subjects.add(samlSubject3);
        if (ipAddress != null) {
            SubjectType samlSubject4 = new SubjectType();
            samlSubject4.setSubjectCategory(
                    "urn:oasis:names:tc:xacml:1.0:subject-category:auxiliary");
            AttributeType subjectAttr4 = new AttributeType();
            subjectAttr4.setAttributeID(
                    "urn:oasis:names:tc:xacml:1.0:subject:ip-address");
            subjectAttr4.setDataType(XACMLConstants.DATATYPE_STRING);
            AttributeValueType subjectAttr4Value =
                    new AttributeValueType();
            subjectAttr4Value.setValue(ipAddress);
            subjectAttr4.setAttributeValues(new AttributeValueType[] {subjectAttr4Value});
            samlSubject4.setAttributes(new AttributeType[] {subjectAttr4});
            subjects.add(samlSubject4);
        }
        samlRequest.setSubjects(subjects.toArray(new SubjectType[subjects.size()]));
//		empty resource
		samlRequest.setResources(new ResourceType[] {new ResourceType()});
//		authenticate action (not required)
		ActionType samlAction = new ActionType();
		AttributeType actionAttr = new AttributeType();
		actionAttr.setAttributeID(XACMLConstants.ACTION_ID);
		actionAttr.setDataType(XACMLConstants.DATATYPE_STRING);
		AttributeValueType actionAttrValue = new AttributeValueType();
		actionAttrValue.setValue("authenticate");
		actionAttr.setAttributeValues(new AttributeValueType[] {actionAttrValue});
		samlAction.setAttributes(new AttributeType[] {actionAttr});
		samlRequest.setAction(samlAction);
//		environment
		EnvironmentType samlEnvironment = new EnvironmentType();
		samlRequest.setEnvironment(samlEnvironment);

		return request;
	}
	
	/**
	 * Builds {@link DNetAuthenticateRequest} object for anonymous logging in.
	 * @param ipAddress
	 * @return {@link DNetAuthenticateRequest} object for anonymous logging in
	 */
	public static DNetAuthenticateRequest buildAnonymousAuthnRequest(String ipAddress) {
		XACMLAuthzDecisionQueryType authnQuery = new XACMLAuthzDecisionQueryType();
		DNetAuthenticateRequest request = new DNetAuthenticateRequest(authnQuery);
		RequestType samlRequest = new RequestType();
		authnQuery.setRequest(samlRequest);
		
		SubjectType samlSubject = new SubjectType();
		samlSubject.setSubjectCategory("urn:oasis:names:tc:xacml:1.0:subject-category:access-subject");
		AttributeType subjectAttr1 = new AttributeType();
		subjectAttr1.setAttributeID(XACMLConstants.SUBJECT_ID);
		subjectAttr1.setDataType(XACMLConstants.DATATYPE_STRING);
		AttributeValueType subjectAttr1Value = new AttributeValueType();
		subjectAttr1Value.setValue("anonymous");
		subjectAttr1.setAttributeValues(new AttributeValueType[] {subjectAttr1Value});
		samlSubject.setAttributes(new AttributeType[] {subjectAttr1});
		
		SubjectType samlSubject4 = new SubjectType();
		samlSubject4.setSubjectCategory("urn:oasis:names:tc:xacml:1.0:subject-category:auxiliary");
		AttributeType subjectAttr4 = new AttributeType();
		subjectAttr4.setAttributeID("urn:oasis:names:tc:xacml:1.0:subject:ip-address");
		subjectAttr4.setDataType(XACMLConstants.DATATYPE_STRING);
		AttributeValueType subjectAttr4Value = new AttributeValueType();
		subjectAttr4Value.setValue(ipAddress);
		subjectAttr4.setAttributeValues(new AttributeValueType[] {subjectAttr4Value});
		samlSubject4.setAttributes(new AttributeType[] {subjectAttr4});
		samlRequest.setSubjects(new SubjectType[] {samlSubject, samlSubject4});
		
//		empty resource
		samlRequest.setResources(new ResourceType[] {new ResourceType()});
//		authenticate action (not required)
		ActionType samlAction = new ActionType();
		AttributeType actionAttr = new AttributeType();
		actionAttr.setAttributeID(XACMLConstants.ACTION_ID);
		actionAttr.setDataType(XACMLConstants.DATATYPE_STRING);
		AttributeValueType actionAttrValue = new AttributeValueType();
		actionAttrValue.setValue("authenticate");
		actionAttr.setAttributeValues(new AttributeValueType[] {actionAttrValue});
		samlAction.setAttributes(new AttributeType[] {actionAttr});
		samlRequest.setAction(samlAction);
//		environment
		EnvironmentType samlEnvironment = new EnvironmentType();
		samlRequest.setEnvironment(samlEnvironment);
		return request;
	}
	
}