/*
 * @(#)Requester.java
 *
 * Copyright (C) 2005 Infocity Inc. All Rights Reserved.
 */
package info.dragonlady.sso;

import info.dragonlady.sso.util.AssertionParser;

import java.util.Date;
import java.util.List;

import org.opensaml.SAMLAction;
import org.opensaml.SAMLAssertion;
import org.opensaml.SAMLAttributeDesignator;
import org.opensaml.SAMLAttributeQuery;
import org.opensaml.SAMLAuthenticationQuery;
import org.opensaml.SAMLAuthorizationDecisionQuery;
import org.opensaml.SAMLBinding;
import org.opensaml.SAMLBindingFactory;
import org.opensaml.SAMLException;
import org.opensaml.SAMLIdentifierFactory;
import org.opensaml.SAMLNameIdentifier;
import org.opensaml.SAMLRequest;
import org.opensaml.SAMLResponse;
import org.opensaml.SAMLSubject;
import org.opensaml.XML;
import org.opensaml.SAMLBrowserProfile.ArtifactMapper;
import org.opensaml.artifact.Artifact;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * SAML要求実行クラス。
 * 
 * @author Hiroshi.Ebata(INFOCITY)
 * @version $Revision: 1.4 $ $Date: 2005/11/17 09:58:40 $
 */
public class Requester implements ArtifactMapper {

	private String responder = null;

	/**
	 * コンストラクタ
	 */
	public Requester(String responder) {
		this.responder = responder;
	}

	/**
	 * SAML要求を送信する。
	 * 
	 * @param request SAML要求
	 * @return SAMLResponse SAML応答
	 * @throws SAMLException
	 * @see org.opensaml.SAMLBrowserProfile.ArtifactMapper#resolve(org.opensaml.SAMLRequest)
	 */
	public SAMLResponse resolve(SAMLRequest request) throws SAMLException {
		SAMLBinding binding = SAMLBindingFactory.getInstance(SAMLBinding.SOAP);
		return binding.send(responder, request);
	}

	/**
	 * 認証問い合わせ要求を作成する。
	 * 
	 * @param artifact アーティファクト
	 * @param assertionIdRef アサーションID参照
	 * @param authId 認証するID
	 * @param confirmationMethod 確認方法
	 * @param confirmationData 確認データ
	 * @param authMethod 認証方法
	 * @return SAMLRequest SAML要求
	 * @throws SAMLException
	 */
	public static final SAMLRequest createAuthenticationRequest(
			Artifact artifact,
			String assertionIdRef,
			String authId,
			String confirmationMethod,
			String confirmationData,
			String authMethod
			) throws SAMLException {
		SAMLSubject subject = new SAMLSubject();
		subject.addConfirmationMethod(confirmationMethod);
		if(artifact == null) {
			SAMLNameIdentifier nameId = new SAMLNameIdentifier();
			nameId.setName(authId);
			subject.setNameIdentifier(nameId);
			Element elm = XML.parserPool.newDocument().createElementNS(XML.SAML_NS, "SubjectConfirmationData");
			elm.setTextContent(confirmationData);
			subject.setConfirmationData(elm);
		}
		SAMLAuthenticationQuery query = new SAMLAuthenticationQuery(subject, authMethod);
		String requestId = SAMLIdentifierFactory.getInstance().getIdentifier();
		SAMLRequest request = new SAMLRequest(query, requestId, new Date());
		if(artifact != null) {
			request.addArtifact(artifact);
		} else if(assertionIdRef != null && assertionIdRef.length() > 0) {
			request.addAssertionIdRef(assertionIdRef);
		}
		return request;
	}

	/**
	 * 属性問い合わせ要求を作成する。
	 * 
	 * @param authAssertion 認証アサーション
	 * @param attributeNames 問い合わせる属性名のリスト
	 * @return SAMLRequest SAML要求
	 * @throws SAMLException
	 */
	public static final SAMLRequest createAttributeRequest(
			SAMLAssertion authAssertion,
			List attributeNames) throws SAMLException {
		SAMLNameIdentifier nameId = new SAMLNameIdentifier();
		nameId.setName(new AssertionParser(authAssertion).getName());
		SAMLSubject subject = new SAMLSubject();
		subject.setNameIdentifier(nameId);
		Document document = XML.parserPool.newDocument();
		Element elm = document.createElementNS(XML.SAML_NS, "SubjectConfirmationData");
		elm.appendChild(authAssertion.toDOM(document));
		subject.setConfirmationData(elm);
		SAMLAttributeQuery query = new SAMLAttributeQuery(subject, null, null);
		for(int i = 0; i < attributeNames.size(); i++) {
			query.addDesignator(new SAMLAttributeDesignator(attributeNames.get(i).toString(), XML.SAML_NS));
		}
		String requestId = SAMLIdentifierFactory.getInstance().getIdentifier();
		SAMLRequest request = new SAMLRequest(query, requestId, new Date());
		return request;
	}

	/**
	 * 認可決定問い合わせ要求を作成する。
	 * 
	 * @param authAssertion 認証アサーション
	 * @param attrAssertion 属性アサーション
	 * @param action リソースへのアクション
	 * @param resource 対象リソース
	 * @return SAMLRequest SAML要求
	 * @throws SAMLException
	 */
	public static final SAMLRequest createAuthorizationDecisionRequest(
			SAMLAssertion authAssertion,
			SAMLAssertion attrAssertion,
			SAMLAction action,
			String resource) throws SAMLException {
		SAMLNameIdentifier nameId = new SAMLNameIdentifier();
		nameId.setName(new AssertionParser(authAssertion).getName());
		SAMLSubject subject = new SAMLSubject();
		subject.setNameIdentifier(nameId);
		SAMLAuthorizationDecisionQuery query = new SAMLAuthorizationDecisionQuery(subject, resource, null, null);
		query.addAction(action);
		query.addEvidence(authAssertion);
		query.addEvidence(attrAssertion);
		String requestId = SAMLIdentifierFactory.getInstance().getIdentifier();
		SAMLRequest request = new SAMLRequest(query, requestId, new Date());
		return request;
	}

}
