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

import info.dragonlady.sso.message.SSOMessageResource;
import info.dragonlady.sso.util.AssertionParser;
import info.dragonlady.sso.util.ResourceParseException;
import info.dragonlady.sso.util.ResourceUtils;

import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

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

import org.opensaml.SAMLAssertion;
import org.opensaml.SAMLBrowserProfile;
import org.opensaml.SAMLBrowserProfileFactory;
import org.opensaml.SAMLBrowserProfile.BrowserProfileRequest;
import org.opensaml.SAMLBrowserProfile.BrowserProfileResponse;
import org.opensaml.artifact.Artifact;
import org.opensaml.artifact.ArtifactParseException;
import org.opensaml.artifact.ArtifactParserException;
import org.opensaml.artifact.SAMLArtifact;
import org.opensaml.artifact.SAMLArtifactType0001;


/**
 * ソースサイトからリダイレクションされた要求を処理するクラス。
 * 
 * @author Hiroshi.Ebata(INFOCITY)
 * @version $Revision: 1.0 $ $Date: 2006/04/13 14:38:14 $
 */
public class ArtifactReceiver {

	private HttpServletRequest request = null;

	private HttpServletResponse response = null;

	private String authId = null;

	private Map<String, List<String>> attributes = null;

	private long expirationTime = 0;

	private String targetUrl = null;

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

	/**
	 * アーティファクトを使用してソースサイトで認証済みかどうか調べ、認証情報を解析する。
	 * 
	 * @throws SSOException
	 */
	public void receive() throws SSOException {
		BrowserProfileResponse bpr = null;
		String artifact = null;
		try {
			SAMLBrowserProfile profile = SAMLBrowserProfileFactory.getInstance();
			BrowserProfileRequest bpReq = profile.receive(request);
			targetUrl = bpReq.TARGET;
			artifact = bpReq.SAMLArt != null && bpReq.SAMLArt.length > 0 ? bpReq.SAMLArt[0] : null;
			bpr = profile.receive(null, bpReq, null, SSOContext.getInstance().getReplayCache(), new Requester(getResponder(artifact)), 1);

			// アサーション解析
			if(bpr != null && bpr.response != null) {
				Iterator<SAMLAssertion> itr = bpr.response.getAssertions();
				while(itr.hasNext()) {
					SAMLAssertion assertion = itr.next();
					AssertionParser parser = new AssertionParser(assertion);
					if(parser.containsAuthenticationStatement()) {
						authId = parser.getName();
						expirationTime = assertion.getNotOnOrAfter().getTime();
					}
					if(parser.containsAttributeStatement()) {
						attributes = parser.getAttribute();
					}
				}
			}
		} catch(Exception e) {
			throw new SSOException(SSOMessageResource.getMessage("1201", new Object[]{targetUrl, artifact}), e);
		}
	}

	/**
	 * アサーションから抽出した認証IDを取得。
	 * 
	 * @return String 認証ID
	 */
	public String getAuthId() {
		return authId;
	}

	/**
	 * アサーションから抽出した属性情報を取得。
	 * 
	 * @return Map<String, List<String>> 属性情報
	 */
	public Map<String, List<String>> getAttributes() {
		return attributes;
	}

	/**
	 * アサーションに設定されていた有効期限を取得。
	 * 
	 * @return long 有効期限
	 */
	public long getExpirationTime() {
		return expirationTime;
	}

	/**
	 * ターゲットURLを取得。
	 * 
	 * @return String ターゲットURL
	 */
	public String getTargetUrl() {
		return targetUrl;
	}

	/**
	 * 要求されたターゲットURLへリダイレクトする。
	 * 
	 * @throws IOException
	 */
	public void redirectToTarget() throws IOException {
		response.sendRedirect(this.targetUrl);
	}

	private String getResponder(String artifactStr) throws ArtifactParseException, ArtifactParserException, ResourceParseException {
		String responder = null;
		Artifact artifact = SAMLArtifact.getTypeCode(artifactStr).getParser().parse(artifactStr);
		if(artifact instanceof SAMLArtifactType0001) {
			String srcId = ResourceUtils.toBase64String(((SAMLArtifactType0001)artifact).getSourceId());
			responder = ResponderResource.getResponder(srcId);
		}
		return responder;
	}

}
