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

import info.dragonlady.sso.util.AssertionGenerator;
import info.dragonlady.sso.util.AssertionParser;

import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.opensaml.SAMLAction;
import org.opensaml.SAMLAssertion;
import org.opensaml.SAMLAuthorizationDecisionQuery;
import org.opensaml.SAMLException;
import org.opensaml.SAMLRequest;
import org.opensaml.SAMLResponse;

/**
 * ポリシー決定点抽象クラス。
 * 
 * @author Hiroshi.Ebata(INFOCITY)
 * @version $Revision: 1.0 $ $Date: 2007/04/25 17:44:33 $
 */
public abstract class PolicyDecisionPoint implements SAMLAuthority {

	/* (non-Javadoc)
	 * @see info.dragonlady.sso.authority.SAMLAuthority#query(org.opensaml.SAMLRequest)
	 */
	public final SAMLResponse query(SAMLRequest request) throws AuthorityException {
		try {
			SAMLResponse response = new SAMLResponse(request.getId(), null, null, null);
			SAMLException samlException = null;
			String authId = null;
			Map<String, List<String>> attributes = Collections.emptyMap();
			Iterator<SAMLAction> requestedAction = null;
			String resource = null;
			try {
				SAMLAuthorizationDecisionQuery query = (SAMLAuthorizationDecisionQuery)request.getQuery();
				Iterator<SAMLAssertion> evidence = query.getEvidence();
				while(evidence.hasNext()) {
					AssertionParser parser = new AssertionParser(evidence.next());
					if(parser.containsAuthenticationStatement()) {
						authId = parser.getName();
					}
					if(parser.containsAttributeStatement()) {
						attributes = parser.getAttribute();
					}
				}
				requestedAction = query.getActions();
				resource = query.getResource();
			} catch(Exception e) {
				// TODO
				samlException = new SAMLException(SAMLException.REQUESTER, "", e);
			}

			if(samlException == null) {
				try {
					String decision = decide(authId, attributes, requestedAction, resource);
					List<SAMLAction> action = getPermittedAction(authId, attributes, resource);
					SAMLAssertion assertion = AssertionGenerator.generateAuthorizationDecisionAssertion(authId, resource, decision, action);
					response.addAssertion(assertion);
					// TODO
					samlException = new SAMLException(SAMLException.SUCCESS, "");
				} catch(Exception e) {
					// TODO
					samlException = new SAMLException(SAMLException.RESPONDER, "", e);
				}
			}
			response.setStatus(samlException);
			return response;
		} catch(Exception e) {
			// TODO
			throw new AuthorityException(e);
		}
	}

	/**
	 * 認可決定処理。
	 * 
	 * @param authId 認証ID
	 * @param attributes 属性情報
	 * @param requestedAction 要求アクション
	 * @param resource リソース
	 * @return String 認可決定情報
	 * @throws AuthorityException
	 */
	protected abstract String decide(
			String authId,
			Map<String, List<String>> attributes,
			Iterator<SAMLAction> requestedAction,
			String resource) throws AuthorityException;

	/**
	 * 許可されたアクションを取得する。
	 * 
	 * @param authId 認証ID
	 * @param attributes 属性情報
	 * @param resource リソース
	 * @return List<SAMLAction> 許可されたアクション
	 * @throws AuthorityException
	 */
	protected abstract List<SAMLAction> getPermittedAction(
			String authId,
			Map<String, List<String>> attributes,
			String resource) throws AuthorityException;

}
