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

import info.dragonlady.cluster.AssertionServiceWrapper;
import info.dragonlady.sso.helper.AttributeGenerator;
import info.dragonlady.sso.helper.AuthenticationException;
import info.dragonlady.sso.helper.Authenticator;
import info.dragonlady.sso.helper.GenerationException;
import info.dragonlady.sso.message.SSOMessageResource;
import info.dragonlady.sso.util.AssertionGenerator;

import java.io.IOException;
import java.util.Arrays;
import java.util.Map;
import java.util.Map.Entry;

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

import org.opensaml.SAMLAssertion;
import org.opensaml.SAMLAuthenticationStatement;
import org.opensaml.SAMLSubject;
import org.opensaml.artifact.Artifact;

import info.dragonlady.sso.AssertionManager;
import info.dragonlady.sso.SSOConfig;
import info.dragonlady.sso.SSOException;
import info.dragonlady.sso.SiteTransfer;

/**
 * サイト転送処理サーブレット。
 * 
 * @author Hiroshi.Ebata(INFOCITY)
 * @version $Revision: 1.0 $ $Date: 2006/10/19 17:38:54 $
 */
public class SiteTransferServlet extends SSOBaseServlet {

	/**
	 * 
	 */
	private static final long serialVersionUID = -6027017224919602614L;

	protected String paramNameAuthClass = "auth-class";

	protected String paramNameAttrClass = "attr-class";

	protected String paramNameProfileType = "profile-type";

	protected String paramNameForwardPath = "forward-path";

	/**
	 * コンストラクタ。
	 */
	public SiteTransferServlet() {
		super();
	}

	/**
	 * サイト転送処理。
	 * 
	 * @param request HTTP要求オブジェクト
	 * @param response HTTP応答オブジェクト
	 * @throws ServletException
	 * @throws IOException
	 * @see info.dragonlady.sso.servlet.SSOBaseServlet#process(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
	 */
	protected void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		try {
			// アサーションID
			String id = null;
			// ユーザの認証ID
			String authId = null;
			String authClass = this.getInitParameter(this.paramNameAuthClass);
			if(authClass != null && authClass.length() > 0) {
				Authenticator authenticator = (Authenticator)Class.forName(authClass).newInstance();
				if(!authenticator.authenticate(request)) {
					throw new AuthenticationException(SSOMessageResource.getMessage("5001"));
				}
			}
			authId = (String)request.getSession().getAttribute(SSOConfig.getLoginKey()); // セッション内から認証IDを取得

			// 目的サイトへ送信するパラメータ
			Map<String, String> attributes = null;
			String attrClass = this.getInitParameter(this.paramNameAttrClass);
			if(attrClass != null && attrClass.length() > 0) {
				AttributeGenerator attrGenerator = (AttributeGenerator)Class.forName(attrClass).newInstance();
				attributes = attrGenerator.generateAttributesMap(request);
			}

			// 認証アサーション作成及び目的サイトへのリダイレクト
			SiteTransfer st = new SiteTransfer(request, response);
			String profileType = this.getInitParameter(this.paramNameProfileType);
			if(profileType.toUpperCase().equals("ARTIFACT")) {
				// Artifactプロファイル
				SAMLAssertion assertion = AssertionGenerator.generateAuthenticationAssertion(authId, SAMLSubject.CONF_ARTIFACT, SAMLAuthenticationStatement.AuthenticationMethod_Unspecified);
				Artifact artifact = AssertionGenerator.generateArtifact(AssertionManager.getInstance().add(assertion));
				st.forward(Arrays.asList(new Artifact[]{artifact}), attributes);
				id = assertion.getId();
			} else if(profileType.toUpperCase().equals("POST")) {
				// POSTプロファイル
				SAMLAssertion assertion = AssertionGenerator.generateAuthenticationAssertion(authId, SAMLSubject.CONF_BEARER, SAMLAuthenticationStatement.AuthenticationMethod_Unspecified);
				Map<String, Object> data = st.getPostData(Arrays.asList(new SAMLAssertion[]{assertion}), attributes);
				for(Entry<String, Object> entry : data.entrySet()) {
					request.getSession().setAttribute(entry.getKey(), entry.getValue());
				}
				request.getRequestDispatcher(this.getInitParameter(this.paramNameForwardPath)).forward(request, response);
			}

			// 分散環境でのアサーション共有処理
			if(!SSOConfig.isClusterStandalone()) {
				if(id != null) {
					AssertionServiceWrapper.put(AssertionManager.getInstance().get(id));
				}
			}
		} catch(AuthenticationException e) {
			processException(SSOMessageResource.getMessage("5002"), e, response, HttpServletResponse.SC_FORBIDDEN);
		} catch(GenerationException e) {
			processException(SSOMessageResource.getMessage("5003"), e, response, HttpServletResponse.SC_FORBIDDEN);
		} catch(SSOException e) {
			processException(SSOMessageResource.getMessage("5004"), e, response, HttpServletResponse.SC_FORBIDDEN);
		} catch(Exception e) {
			processException(SSOMessageResource.getMessage("5005"), e, response, HttpServletResponse.SC_NOT_FOUND);
		}
	}

}
