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

import info.dragonlady.sso.authority.AuthorityException;
import info.dragonlady.sso.authority.EnforcementException;
import info.dragonlady.sso.authority.PolicyEnforcementPoint;
import info.dragonlady.sso.authority.SAMLAuthorityProvider;
import info.dragonlady.sso.util.AssertionParser;
import info.dragonlady.sso.util.ResourceParseException;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.opensaml.SAMLAction;
import org.opensaml.SAMLAssertion;
import org.opensaml.SAMLAuthenticationStatement;
import org.opensaml.SAMLBrowserProfile;
import org.opensaml.SAMLBrowserProfileFactory;
import org.opensaml.SAMLException;
import org.opensaml.SAMLRequest;
import org.opensaml.SAMLResponse;
import org.opensaml.SAMLSubject;
import org.opensaml.SAMLBrowserProfile.BrowserProfileRequest;
import org.opensaml.SAMLBrowserProfile.BrowserProfileResponse;

/**
 * アサーション消費者。
 * 
 * @author Hiroshi.Ebata(INFOCITY)
 * @version $Revision: 1.0 $ $Date: 2007/04/19 17:38:34 $
 */
public class AssertionConsumer implements PolicyEnforcementPoint {

	private HttpServletRequest request = null;

	private HttpServletResponse response = null;

	private String resource = null;

	/**
	 * コンストラクタ
	 * 
	 * @param request 要求オブジェクト
	 * @param response 応答オブジェクト
	 */
	public AssertionConsumer(HttpServletRequest request, HttpServletResponse response) {
		super();
		this.request = request;
		this.response = response;
		this.resource = request.getParameter(SSOConstants.NAME_TARGET);
	}

	/* (non-Javadoc)
	 * @see info.dragonlady.sso.authority.PolicyEnforcementPoint#isEnforceable()
	 */
	public boolean isEnforceable() throws EnforcementException {
		try {
			// 受取人（自身）
			String recipient = ConsumerResource.getConsumer(request.getServerName(), request.getContextPath().replace("/", ""));
			SAMLBrowserProfile profile = SAMLBrowserProfileFactory.getInstance();
			BrowserProfileRequest bpReq = profile.receive(request);
			BrowserProfileResponse bpRes = profile.receive(null, bpReq, recipient, SSOContext.getInstance().getReplayCache(), null, 1);
			// 署名確認
			if(bpRes.assertion.isSigned()) {
				bpRes.assertion.verify();
			}
			return verify(bpRes.assertion, resource);
		} catch(Exception e) {
			throw new EnforcementException(e);
		}
	}

	private boolean verify(SAMLAssertion assertion, String resource) throws SAMLException, AuthorityException, ResourceParseException, InstantiationException, IllegalAccessException, ClassNotFoundException, CloneNotSupportedException {
		// 認証オーソリティ問い合わせ
		SAMLRequest samlRequest = Requester.createAuthenticationRequest(null, null, new AssertionParser(assertion).getName(), SAMLSubject.CONF_BEARER, assertion.toString(), SAMLAuthenticationStatement.AuthenticationMethod_XML_DSig);
		SAMLResponse samlResponse = SAMLAuthorityProvider.getAuthenticationAuthority().query(samlRequest);
		SAMLException status = samlResponse.getStatus();
		if(!status.getCodes().next().equals(SAMLException.SUCCESS)) {
			throw new AuthorityException(status.getMessage(), status.getException());
		}
		SAMLAssertion authAssertion = (SAMLAssertion)samlResponse.getAssertions().next();
		// 属性オーソリティ問い合わせ
		samlRequest = Requester.createAttributeRequest(authAssertion, SSOConfig.getSAMLAttributeList());
		samlResponse = SAMLAuthorityProvider.getAttributeAuthority().query(samlRequest);
		status = samlResponse.getStatus();
		if(!status.getCodes().next().equals(SAMLException.SUCCESS)) {
			throw new AuthorityException(status.getMessage(), status.getException());
		}
		SAMLAssertion attrAssertion = (SAMLAssertion)samlResponse.getAssertions().next();
		// ポリシー決定点問い合わせ
		samlRequest = Requester.createAuthorizationDecisionRequest((SAMLAssertion)authAssertion.clone(), (SAMLAssertion)attrAssertion.clone(), new SAMLAction(SAMLAction.SAML_ACTION_NAMESPACE_GHPP, SSOConstants.ACTION_GET), resource);
		samlResponse = SAMLAuthorityProvider.getPolicyDecisionPoint().query(samlRequest);
		status = samlResponse.getStatus();
		if(!status.getCodes().next().equals(SAMLException.SUCCESS)) {
			throw new AuthorityException(status.getMessage(), status.getException());
		}

		AssertionParser parser = new AssertionParser((SAMLAssertion)samlResponse.getAssertions().next());
		return parser.isPermitted();
	}

	/* (non-Javadoc)
	 * @see info.dragonlady.sso.authority.PolicyEnforcementPoint#enforce()
	 */
	public void enforce() throws EnforcementException {
		try {
			if(isEnforceable()) {
				response.addCookie(new Cookie(SSOConstants.NAME_SESSIONID.toUpperCase(), request.getSession().getId()));
				response.sendRedirect(resource);
			}
		} catch(Exception e) {
			throw new EnforcementException(e);
		}
	}

}
