io.personium.core.rs.cell.AuthzEndPointResource.java Source code

Java tutorial

Introduction

Here is the source code for io.personium.core.rs.cell.AuthzEndPointResource.java

Source

/**
 * personium.io
 * Copyright 2014 FUJITSU LIMITED
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.personium.core.rs.cell;

import static io.personium.common.auth.token.AbstractOAuth2Token.MILLISECS_IN_AN_HOUR;

import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLEncoder;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.OPTIONS;
import javax.ws.rs.POST;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Cookie;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.NewCookie;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.UriInfo;

import org.apache.commons.lang.CharEncoding;
import org.apache.commons.lang.StringUtils;
import org.odata4j.core.OEntityKey;
import org.odata4j.edm.EdmEntitySet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sun.jersey.api.client.ClientResponse.Status;

import io.personium.common.auth.token.AbstractOAuth2Token;
import io.personium.common.auth.token.AbstractOAuth2Token.TokenDsigException;
import io.personium.common.auth.token.AbstractOAuth2Token.TokenParseException;
import io.personium.common.auth.token.AbstractOAuth2Token.TokenRootCrtException;
import io.personium.common.auth.token.AccountAccessToken;
import io.personium.common.auth.token.CellLocalAccessToken;
import io.personium.common.auth.token.CellLocalRefreshToken;
import io.personium.common.auth.token.IAccessToken;
import io.personium.common.auth.token.IExtRoleContainingToken;
import io.personium.common.auth.token.IRefreshToken;
import io.personium.common.auth.token.Role;
import io.personium.common.auth.token.TransCellAccessToken;
import io.personium.common.auth.token.UnitLocalUnitUserToken;
import io.personium.common.utils.PersoniumCoreUtils;
import io.personium.core.PersoniumCoreAuthnException;
import io.personium.core.PersoniumCoreException;
import io.personium.core.PersoniumCoreLog;
import io.personium.core.PersoniumCoreMessageUtils;
import io.personium.core.PersoniumUnitConfig;
import io.personium.core.auth.OAuth2Helper;
import io.personium.core.auth.OAuth2Helper.Key;
import io.personium.core.model.Box;
import io.personium.core.model.Cell;
import io.personium.core.model.DavRsCmp;
import io.personium.core.model.ModelFactory;
import io.personium.core.model.ctl.Account;
import io.personium.core.model.impl.es.EsModel;
import io.personium.core.model.impl.es.QueryMapFactory;
import io.personium.core.model.impl.es.accessor.EntitySetAccessor;
import io.personium.core.model.impl.es.doc.OEntityDocHandler;
import io.personium.core.odata.OEntityWrapper;
import io.personium.core.odata.PersoniumODataProducer;

/**
 * ImplicitFlow???JAX-RS.
 */
public class AuthzEndPointResource {

    private static final int COOKIE_MAX_AGE = 86400;

    private static final String PROFILE_JSON_NAME = "/profile.json";

    /**
     * .
     */
    static Logger log = LoggerFactory.getLogger(AuthzEndPointResource.class);

    private final Cell cell;
    private final DavRsCmp davRsCmp;

    /**
     * _Javascript.
     */
    private final String jsFileName = "ajax.js";

    /**
     * _?.
     */
    private final String passFormMsg = PersoniumCoreMessageUtils.getMessage("PS-AU-0002");

    /**
     * _ID?.
     */
    private final String noIdPassMsg = PersoniumCoreMessageUtils.getMessage("PS-AU-0003");

    /**
     * Cookie??.
     */
    private final String missCookieMsg = PersoniumCoreMessageUtils.getMessage("PS-AU-0005");

    /**
     * ???Account?UUID?????.
     */
    private String accountId;

    /**
     * .
     * @param cell Cell
     * @param davRsCmp davRsCmp
     */
    public AuthzEndPointResource(final Cell cell, final DavRsCmp davRsCmp) {
        this.cell = cell;
        this.davRsCmp = davRsCmp;
    }

    /**
     * ???. <h2>????</h2>
     * <ul>
     * <li>p_target?URL?????????CELLTARGET?CELL???transCellToken?</li>
     * </ul>
     * @param authzHeader Authorization 
     * @param pOwner 
     * @param username 
     * @param password 
     * @param pTarget 
     * @param assertion 
     * @param clientId 
     * @param responseType 
     * @param redirectUri 
     * @param host Host
     * @param cookieRefreshToken 
     * @param keepLogin 
     * @param state 
     * @param isCancel Cancel
     * @param uriInfo 
     * @return JAX-RS Response Object
     */
    @POST
    public final Response authPost(@HeaderParam(HttpHeaders.AUTHORIZATION) final String authzHeader,
            @FormParam(Key.OWNER) final String pOwner, @FormParam(Key.USERNAME) final String username,
            @FormParam(Key.PASSWORD) final String password, @FormParam(Key.TARGET) final String pTarget,
            @FormParam(Key.ASSERTION) final String assertion, @FormParam(Key.CLIENT_ID) final String clientId,
            @FormParam(Key.RESPONSE_TYPE) final String responseType,
            @FormParam(Key.REDIRECT_URI) final String redirectUri, @HeaderParam(HttpHeaders.HOST) final String host,
            @HeaderParam(Key.SESSION_ID) final String cookieRefreshToken,
            @FormParam(Key.KEEPLOGIN) final String keepLogin, @FormParam(Key.STATE) final String state,
            @FormParam(Key.CANCEL_FLG) final String isCancel, @Context final UriInfo uriInfo) {

        return auth(pOwner, username, password, pTarget, assertion, clientId, responseType, redirectUri, host,
                cookieRefreshToken, keepLogin, state, isCancel, uriInfo);
    }

    private Response auth(final String pOwner, final String username, final String password, final String pTarget,
            final String assertion, final String clientId, final String responseType, final String redirectUri,
            final String host, final String cookieRefreshToken, final String keepLogin, final String state,
            final String isCancel, final UriInfo uriInfo) {

        String normalizedRedirectUri = redirectUri;
        String normalizedClientId = clientId;
        if (redirectUri == null || "".equals(redirectUri)) {
            return this.returnErrorRedirect(cell.getUrl() + "__html/error", "PR400-AZ-0003");
        } else {
            // "/"?
            if (!redirectUri.endsWith("/")) {
                normalizedRedirectUri = redirectUri + "/";
            }
        }
        if (clientId == null || "".equals(clientId)) {
            return this.returnErrorRedirect(cell.getUrl() + "__html/error", "PR400-AZ-0002");
        } else {
            if (!clientId.endsWith("/")) {
                normalizedClientId = clientId + "/";
            }
        }

        // ???
        // clientId???URL???Box????
        //
        if (!checkAuthorization(normalizedClientId)) {
            log.debug(PersoniumCoreMessageUtils.getMessage("PS-ER-0003"));
            return this.returnErrorRedirect(cell.getUrl() + "__html/error", "PS-ER-0003");
        }

        // clientId?redirectUri?
        try {
            this.checkImplicitParam(normalizedClientId, normalizedRedirectUri, uriInfo.getBaseUri());
        } catch (PersoniumCoreException e) {
            log.debug(e.getMessage());
            if ((username == null && password == null) //NOPMD -To maintain readability
                    && (assertion == null || "".equals(assertion)) && cookieRefreshToken == null) {
                // IDassertioncookie?????
                throw e;
            } else {
                return this.returnErrorRedirect(cell.getUrl() + "__html/error", e.getCode());
            }
        }

        if ("1".equals(isCancel)) {
            // redirect_uri?
            return this.returnErrorRedirect(redirectUri, OAuth2Helper.Error.UNAUTHORIZED_CLIENT,
                    PersoniumCoreMessageUtils.getMessage("PR401-AZ-0001"), state, "PR401-AZ-0001");
        }

        String schema = clientId;

        // response_Type??
        if (responseType == null) {
            // redirect_uri?
            return this.returnErrorRedirect(redirectUri, OAuth2Helper.Error.INVALID_REQUEST,
                    OAuth2Helper.Error.INVALID_REQUEST, state, "PR400-AZ-0004");
        } else if (!OAuth2Helper.ResponseType.TOKEN.equals(responseType)) {
            // redirect_uri?
            return this.returnErrorRedirect(redirectUri, OAuth2Helper.Error.UNSUPPORTED_RESPONSE_TYPE,
                    OAuth2Helper.Error.UNSUPPORTED_RESPONSE_TYPE, state, "PR400-AZ-0001");
        } else {
            return this.handleImplicitFlow(redirectUri, clientId, host, username, password, cookieRefreshToken,
                    pTarget, keepLogin, assertion, schema, state, pOwner);
        }
    }

    /**
     * ???. <h2>????</h2>
     * <ul>
     * <li>p_target?URL?????????CELLTARGET?CELL???transCellToken?</li>
     * </ul>
     * @param authzHeader Authorization 
     * @param pTarget 
     * @param pOwner 
     * @param assertion 
     * @param clientId 
     * @param responseType 
     * @param redirectUri 
     * @param host Host
     * @param cookieRefreshToken 
     * @param keepLogin 
     * @param state 
     * @param isCancel Cancel
     * @param uriInfo 
     * @return JAX-RS Response Object
     */
    @GET
    public final Response authGet(@HeaderParam(HttpHeaders.AUTHORIZATION) final String authzHeader,
            @QueryParam(Key.TARGET) final String pTarget, @QueryParam(Key.OWNER) final String pOwner,
            @QueryParam(Key.ASSERTION) final String assertion, @QueryParam(Key.CLIENT_ID) final String clientId,
            @QueryParam(Key.RESPONSE_TYPE) final String responseType,
            @QueryParam(Key.REDIRECT_URI) final String redirectUri,
            @HeaderParam(HttpHeaders.HOST) final String host,
            @HeaderParam(Key.SESSION_ID) final String cookieRefreshToken,
            @QueryParam(Key.KEEPLOGIN) final String keepLogin, @QueryParam(Key.STATE) final String state,
            @QueryParam(Key.CANCEL_FLG) final String isCancel, @Context final UriInfo uriInfo) {

        return auth(pOwner, null, null, pTarget, assertion, clientId, responseType, redirectUri, host,
                cookieRefreshToken, keepLogin, state, isCancel, uriInfo);

    }

    private void checkPTarget(final String pTarget) {
        String target = pTarget;
        if (target != null && !"".equals(pTarget)) {
            try {
                new URL(target);
                if (!target.endsWith("/")) {
                    target = target + "/";
                }
                if (target.contains("\n") || target.contains("\r")) {
                    // p_target?URL?????
                    throw PersoniumCoreAuthnException.INVALID_TARGET;
                }
            } catch (MalformedURLException e) {
                // p_target?URL?????
                throw PersoniumCoreAuthnException.INVALID_TARGET;
            }
        }
    }

    /**
     * ImplicitFlow?.
     * @param clientId clientId
     * @param redirectUriStr redirectUriStr
     * @param message ??
     * @param state state
     * @param dcTraget dcTraget
     * @param pOwner pOwner
     * @return HTML
     */
    private String createForm(String clientId, String redirectUriStr, String message, String state, String dcTraget,
            String pOwner) {

        List<Object> paramsList = new ArrayList<Object>();

        // "/"?
        if (!"".equals(clientId) && !clientId.endsWith("/")) {
            clientId = clientId + "/";
        }

        // 
        paramsList.add(PersoniumCoreMessageUtils.getMessage("PS-AU-0001"));
        // ?profile.json
        paramsList.add(clientId + Box.DEFAULT_BOX_NAME + PROFILE_JSON_NAME);
        // ?profile.json
        paramsList.add(cell.getUrl() + Box.DEFAULT_BOX_NAME + PROFILE_JSON_NAME);
        // 
        paramsList.add(PersoniumCoreMessageUtils.getMessage("PS-AU-0001"));
        // ??
        paramsList.add(cell.getUrl() + "__authz");
        // 
        paramsList.add(message);
        // hidden
        paramsList.add(state);
        if (dcTraget == null) {
            paramsList.add("");
        } else {
            paramsList.add(dcTraget);
        }
        if (pOwner == null) {
            paramsList.add("");
        } else {
            paramsList.add(pOwner);
        }
        paramsList.add(clientId);
        paramsList.add(redirectUriStr);
        paramsList.add(AuthResourceUtils.getJavascript(jsFileName));

        Object[] params = paramsList.toArray();

        String html = PersoniumCoreUtils.readStringResource("html/authform.html", CharEncoding.UTF_8);
        html = MessageFormat.format(html, params);

        return html;
    }

    /**
     * ImplicitFlow???.
     * @param pTarget
     * @param redirectUriStr
     * @param clientId
     * @param username
     * @param password
     * @param keepLogin
     * @param state
     * @param pOwner
     * @param host
     * @return
     */
    private Response handleImplicitFlowPassWord(final String pTarget, final String redirectUriStr,
            final String clientId, final String username, final String password, final String keepLogin,
            final String state, final String pOwner, final String host) {

        // ID????????
        boolean passCheck = true;
        if (username == null || password == null || "".equals(username) || "".equals(password)) {
            ResponseBuilder rb = Response.ok().type(MediaType.TEXT_HTML);
            return rb.entity(this.createForm(clientId, redirectUriStr, noIdPassMsg, state, pTarget, pOwner))
                    .header("Content-Type", "text/html; charset=UTF-8").build();
        }

        OEntityWrapper oew = cell.getAccount(username);
        if (oew == null) {
            String resCode = "PS-AU-0004";
            String missIdPassMsg = PersoniumCoreMessageUtils.getMessage(resCode);
            log.info("MessageCode : " + resCode);
            log.info("responseMessage : " + missIdPassMsg);
            ResponseBuilder rb = Response.ok().type(MediaType.TEXT_HTML);
            return rb.entity(this.createForm(clientId, redirectUriStr, missIdPassMsg, state, pTarget, pOwner))
                    .header("Content-Type", "text/html; charset=UTF-8").build();
        }
        // ?????UUID????????
        accountId = (String) oew.getUuid();

        // ??
        Boolean isLock = true;
        try {
            isLock = AuthResourceUtils.isLockedAccount(accountId);
            if (isLock) {
                // memcached?
                AuthResourceUtils.registAccountLock(accountId);
                String resCode = "PS-AU-0006";
                String accountLockMsg = PersoniumCoreMessageUtils.getMessage(resCode);
                log.info("MessageCode : " + resCode);
                log.info("responseMessage : " + accountLockMsg);
                ResponseBuilder rb = Response.ok().type(MediaType.TEXT_HTML);
                return rb.entity(this.createForm(clientId, redirectUriStr, accountLockMsg, state, pTarget, pOwner))
                        .header("Content-Type", "text/html; charset=UTF-8").build();
            }

            // ID???
            passCheck = cell.authenticateAccount(oew, password);
            if (!passCheck) {
                // memcached??
                AuthResourceUtils.registAccountLock(accountId);
                String resCode = "PS-AU-0004";
                String missIdPassMsg = PersoniumCoreMessageUtils.getMessage(resCode);
                log.info("MessageCode : " + resCode);
                log.info("responseMessage : " + missIdPassMsg);
                ResponseBuilder rb = Response.ok().type(MediaType.TEXT_HTML);
                return rb.entity(this.createForm(clientId, redirectUriStr, missIdPassMsg, state, pTarget, pOwner))
                        .header("Content-Type", "text/html; charset=UTF-8").build();
            }
        } catch (PersoniumCoreException e) {
            return this.returnErrorRedirect(redirectUriStr, e.getMessage(), e.getMessage(), state, e.getCode());
        }

        long issuedAt = new Date().getTime();
        String schema = clientId;

        AbstractOAuth2Token localToken = null;

        if (Key.TRUE_STR.equals(pOwner)) {
            // ???
            if (!this.davRsCmp.checkOwnerRepresentativeAccounts(username)) {
                return returnErrorMessage(clientId, redirectUriStr, passFormMsg, state, pTarget, pOwner);
            }
            // ???????????
            if (cell.getOwner() == null) {
                return returnErrorMessage(clientId, redirectUriStr, passFormMsg, state, pTarget, pOwner);
            }

            // uluut?
            localToken = new UnitLocalUnitUserToken(issuedAt,
                    UnitLocalUnitUserToken.ACCESS_TOKEN_EXPIRES_HOUR * MILLISECS_IN_AN_HOUR, cell.getOwner(), host);

        }

        // ??
        CellLocalRefreshToken rToken = new CellLocalRefreshToken(issuedAt,
                CellLocalRefreshToken.REFRESH_TOKEN_EXPIRES_HOUR * MILLISECS_IN_AN_HOUR, cell.getUrl(), username,
                schema);
        // 302????Location?
        try {
            if (localToken != null) {
                // ULUUT??
                UnitLocalUnitUserToken aToken = (UnitLocalUnitUserToken) localToken;
                return returnSuccessRedirect(redirectUriStr, aToken.toTokenString(), aToken.expiresIn(), null, null,
                        state);
            } else {
                // ????
                if (pTarget == null || "".equals(pTarget)) {
                    // ??
                    AccountAccessToken aToken = new AccountAccessToken(issuedAt,
                            AccountAccessToken.ACCESS_TOKEN_EXPIRES_HOUR * MILLISECS_IN_AN_HOUR, cell.getUrl(),
                            username, schema);
                    return returnSuccessRedirect(redirectUriStr, aToken.toTokenString(), aToken.expiresIn(),
                            rToken.toTokenString(), keepLogin, state);
                } else {
                    // ??
                    List<Role> roleList = cell.getRoleListForAccount(username);
                    TransCellAccessToken tcToken = new TransCellAccessToken(cell.getUrl(),
                            cell.getUrl() + "#" + username, pTarget, roleList, schema);
                    return returnSuccessRedirect(redirectUriStr, tcToken.toTokenString(), tcToken.expiresIn(),
                            rToken.toTokenString(), keepLogin, state);
                }
            }
        } catch (MalformedURLException e) {
            return returnErrorMessage(clientId, redirectUriStr, passFormMsg, state, pTarget, pOwner);
        }
    }

    /**
     * ImplicitFlow???.
     * @param redirectUriStr
     * @param clientId
     * @param cookieRefreshToken
     * @param pTarget
     * @param keepLogin
     * @return
     */
    private Response handleImplicitFlowTcToken(final String redirectUriStr, final String clientId,
            final String assertion, final String pTarget, final String keepLogin, final String schema,
            final String state) {

        // ????
        TransCellAccessToken tcToken = null;
        try {
            tcToken = TransCellAccessToken.parse(assertion);
        } catch (TokenParseException e) {
            // 
            PersoniumCoreLog.Auth.TOKEN_PARSE_ERROR.params(e.getMessage()).writeLog();
            return this.returnErrorRedirect(redirectUriStr, OAuth2Helper.Error.ACCESS_DENIED,
                    OAuth2Helper.Error.ACCESS_DENIED, state, "PR401-AZ-0002");
        } catch (TokenDsigException e) {
            // ???
            PersoniumCoreLog.Auth.TOKEN_DISG_ERROR.params(e.getMessage()).writeLog();
            return this.returnErrorRedirect(redirectUriStr, OAuth2Helper.Error.ACCESS_DENIED,
                    OAuth2Helper.Error.ACCESS_DENIED, state, "PR401-AZ-0002");
        } catch (TokenRootCrtException e) {
            // CA?
            PersoniumCoreLog.Auth.ROOT_CA_CRT_SETTING_ERROR.params(e.getMessage()).writeLog();
            return this.returnErrorRedirect(redirectUriStr, OAuth2Helper.Error.ACCESS_DENIED,
                    OAuth2Helper.Error.ACCESS_DENIED, state, "PR401-AZ-0002");
        }

        // Token?
        // 1??
        if (tcToken.isExpired()) {
            return this.returnErrorRedirect(redirectUriStr, OAuth2Helper.Error.ACCESS_DENIED,
                    OAuth2Helper.Error.ACCESS_DENIED, state, "PR401-AZ-0002");
        }

        // ???????
        try {
            if (!(AuthResourceUtils.checkTargetUrl(this.cell, tcToken))) {
                return this.returnErrorRedirect(redirectUriStr, OAuth2Helper.Error.ACCESS_DENIED,
                        OAuth2Helper.Error.ACCESS_DENIED, state, "PR401-AZ-0002");
            }
        } catch (MalformedURLException e) {
            log.debug(e.getMessage());
            return this.returnErrorRedirect(redirectUriStr, OAuth2Helper.Error.ACCESS_DENIED,
                    OAuth2Helper.Error.ACCESS_DENIED, state, "PR401-AZ-0002");
        }

        // ??? -------------------------------

        long issuedAt = new Date().getTime();

        // CELL????TC????????
        List<Role> rolesHere = cell.getRoleListHere(tcToken);

        String schemaVerified = schema;

        // ??
        // ?????
        IAccessToken aToken = null;
        if (pTarget == null || "".equals(pTarget)) {
            aToken = new CellLocalAccessToken(issuedAt, cell.getUrl(), tcToken.getSubject(), rolesHere,
                    schemaVerified);
        } else {
            aToken = new TransCellAccessToken(UUID.randomUUID().toString(), issuedAt, cell.getUrl(),
                    tcToken.getSubject(), pTarget, rolesHere, schemaVerified);
        }
        // ????
        // 302????Location?
        try {
            return returnSuccessRedirect(redirectUriStr, aToken.toTokenString(), aToken.expiresIn(), null,
                    keepLogin, state);
        } catch (MalformedURLException e) {
            return returnErrorMessage(clientId, redirectUriStr, passFormMsg, state, pTarget, "");
        }
    }

    /**
     * ImplicitFlow?cookie??.
     * @param redirectUriStr
     * @param clientId
     * @param host
     * @param cookieRefreshToken
     * @param pTarget
     * @param keepLogin
     * @return
     */
    private Response handleImplicitFlowcookie(final String redirectUriStr, final String clientId, final String host,
            final String cookieRefreshToken, final String pTarget, final String keepLogin, final String state,
            final String pOwner) {
        IRefreshToken rToken = null;
        IAccessToken aToken = null;
        try {
            AbstractOAuth2Token token = AbstractOAuth2Token.parse(cookieRefreshToken, cell.getUrl(), host);
            if (!(token instanceof IRefreshToken)) {
                return returnErrorMessage(clientId, redirectUriStr, missCookieMsg, state, pTarget, pOwner);
            }

            // ???
            if (token.isRefreshExpired()) {
                return returnErrorMessage(clientId, redirectUriStr, missCookieMsg, state, pTarget, pOwner);
            }

            long issuedAt = new Date().getTime();

            if (Key.TRUE_STR.equals(pOwner)) {
                // ???????
                if (token.getClass() != CellLocalRefreshToken.class) {
                    return returnErrorMessage(clientId, redirectUriStr, missCookieMsg, state, pTarget, pOwner);
                }
                // ???
                if (!this.davRsCmp.checkOwnerRepresentativeAccounts(token.getSubject())) {
                    return returnErrorMessage(clientId, redirectUriStr, missCookieMsg, state, pTarget, pOwner);
                }
                // ???????????
                if (cell.getOwner() == null) {
                    return returnErrorMessage(clientId, redirectUriStr, missCookieMsg, state, pTarget, pOwner);
                }

                // uluut?
                UnitLocalUnitUserToken uluut = new UnitLocalUnitUserToken(issuedAt,
                        UnitLocalUnitUserToken.ACCESS_TOKEN_EXPIRES_HOUR * MILLISECS_IN_AN_HOUR, cell.getOwner(),
                        host);
                // Cookie????
                // 302????Location?
                try {
                    return returnSuccessRedirect(redirectUriStr, uluut.toTokenString(), uluut.expiresIn(), null,
                            keepLogin, state);
                } catch (MalformedURLException e) {
                    return returnErrorMessage(clientId, redirectUriStr, missCookieMsg, state, pTarget, pOwner);
                }
            } else {
                // ?????Refresh Token? AccessToken?RefreshToken??
                rToken = (IRefreshToken) token;
                rToken = rToken.refreshRefreshToken(issuedAt);

                if (rToken instanceof CellLocalRefreshToken) {
                    String subject = rToken.getSubject();
                    List<Role> roleList = cell.getRoleListForAccount(subject);
                    aToken = rToken.refreshAccessToken(issuedAt, pTarget, cell.getUrl(), roleList);
                } else {
                    // CELL????????????
                    List<Role> rolesHere = cell.getRoleListHere((IExtRoleContainingToken) rToken);
                    aToken = rToken.refreshAccessToken(issuedAt, pTarget, cell.getUrl(), rolesHere);
                }
            }

        } catch (TokenParseException e) {
            // ?????
            PersoniumCoreLog.Auth.TOKEN_PARSE_ERROR.params(e.getMessage()).writeLog();
            return returnErrorMessage(clientId, redirectUriStr, missCookieMsg, state, pTarget, pOwner);
        } catch (TokenDsigException e) {
            // ?????
            PersoniumCoreLog.Auth.TOKEN_DISG_ERROR.params(e.getMessage()).writeLog();
            return returnErrorMessage(clientId, redirectUriStr, missCookieMsg, state, pTarget, pOwner);
        } catch (TokenRootCrtException e) {
            // CA?
            PersoniumCoreLog.Auth.ROOT_CA_CRT_SETTING_ERROR.params(e.getMessage()).writeLog();
            return returnErrorMessage(clientId, redirectUriStr, missCookieMsg, state, pTarget, pOwner);
        }
        // Cookie????
        // 302????Location?
        try {
            return returnSuccessRedirect(redirectUriStr, aToken.toTokenString(), aToken.expiresIn(),
                    rToken.toTokenString(), keepLogin, state);
        } catch (MalformedURLException e) {
            return returnErrorMessage(clientId, redirectUriStr, missCookieMsg, state, pTarget, pOwner);
        }
    }

    /**
     * ImplicitFlow????.
     * @param redirectUriStr
     * @param clientId
     * @param host
     * @param username
     * @param password
     * @param cookieRefreshToken
     * @param pTarget
     * @param keepLogin
     * @param assertion
     * @param state
     * @param pOwner TODO
     * @return
     */
    private Response handleImplicitFlow(final String redirectUriStr, final String clientId, final String host,
            final String username, final String password, final String cookieRefreshToken, final String pTarget,
            final String keepLogin, final String assertion, final String schema, final String state,
            final String pOwner) {

        // p_target ?URL?????Injection?????(??????)
        try {
            this.checkPTarget(pTarget);
        } catch (PersoniumCoreAuthnException e) {
            return this.returnErrorRedirect(redirectUriStr, OAuth2Helper.Error.INVALID_REQUEST, e.getMessage(),
                    state, "code");
        }
        // TODO ????????????Box?
        // ????Box???????

        // ??cookie???
        if (username != null || password != null) {
            // ID????????
            Response response = this.handleImplicitFlowPassWord(pTarget, redirectUriStr, clientId, username,
                    password, keepLogin, state, pOwner, host);

            if (PersoniumUnitConfig.getAccountLastAuthenticatedEnable() && isSuccessAuthorization(response)) {
                // Account???
                PersoniumODataProducer producer = ModelFactory.ODataCtl.cellCtl(cell);
                EdmEntitySet esetAccount = producer.getMetadata().getEdmEntitySet(Account.EDM_TYPE_NAME);
                OEntityKey originalKey = OEntityKey.parse("('" + username + "')");
                // ?Producer??(????)
                producer.updateLastAuthenticated(esetAccount, originalKey, accountId);
            }
            return response;
        } else if (assertion != null && !"".equals(assertion)) {
            // assertion????
            return this.handleImplicitFlowTcToken(redirectUriStr, clientId, assertion, pTarget, keepLogin, schema,
                    state);
        } else if (cookieRefreshToken != null) {
            // cookie????
            // cookie????keepLogin??true????
            return this.handleImplicitFlowcookie(redirectUriStr, clientId, host, cookieRefreshToken, pTarget,
                    OAuth2Helper.Key.TRUE_STR, state, pOwner);
        } else {
            // IDassertioncookie?????
            ResponseBuilder rb = Response.ok().type(MediaType.TEXT_HTML);
            return rb.entity(this.createForm(clientId, redirectUriStr, passFormMsg, state, pTarget, pOwner))
                    .header("Content-Type", "text/html; charset=UTF-8").build();
        }
    }

    /**
     * ImplicitFlow????????????.
     * @param response ??
     * @return true: ?? false:?
     */
    protected boolean isSuccessAuthorization(Response response) {
        // ??302?????????????
        if (Status.FOUND.getStatusCode() != response.getStatus()) {
            return false;
        }

        // Location???URL???????
        String locationStr = (String) response.getMetadata().getFirst(HttpHeaders.LOCATION);
        try {
            URI uri = new URI(locationStr);
            String fragment = uri.getFragment();
            // ?????API?I/F????
            if (null == fragment) {
                return false;
            }
            if (fragment.indexOf(OAuth2Helper.Key.ERROR + "=") >= 0
                    && fragment.indexOf(OAuth2Helper.Key.ERROR_DESCRIPTION + "=") >= 0
                    && fragment.indexOf(OAuth2Helper.Key.STATE + "=") >= 0
                    && fragment.indexOf(OAuth2Helper.Key.CODE + "=") >= 0) {
                return false;
            }
        } catch (URISyntaxException e) {
            return false;
        }
        return true;
    }

    /**
     * ImplicitFlow????Redirect?.
     * @param redirectUriStr
     * @param localTokenStr
     * @param localTokenExpiresIn
     * @param refreshTokenStr
     * @param keepLogin
     * @param state
     * @return
     * @throws MalformedURLException
     */
    private Response returnSuccessRedirect(String redirectUriStr, String localTokenStr, int localTokenExpiresIn,
            String refreshTokenStr, String keepLogin, String state) throws MalformedURLException {
        // 302????Location?
        ResponseBuilder rb = Response.status(Status.FOUND).type(MediaType.APPLICATION_JSON_TYPE);
        rb.header(HttpHeaders.LOCATION,
                redirectUriStr + "#" + OAuth2Helper.Key.ACCESS_TOKEN + "=" + localTokenStr + "&"
                        + OAuth2Helper.Key.TOKEN_TYPE + "=" + OAuth2Helper.Scheme.BEARER + "&"
                        + OAuth2Helper.Key.EXPIRES_IN + "=" + localTokenExpiresIn + "&" + OAuth2Helper.Key.STATE
                        + "=" + state);
        // ???

        // ??????cookie??
        URL cellUrl = new URL(cell.getUrl());
        NewCookie cookies = null;
        Cookie cookie = new Cookie(OAuth2Helper.Key.SESSION_ID, refreshTokenStr, cellUrl.getPath(), null);
        if (refreshTokenStr != null) {
            // ?????SSL????Cookie?
            // ?https?????secure?
            if (OAuth2Helper.Key.TRUE_STR.equals(keepLogin)) {
                // Cookie??24?
                cookies = new NewCookie(cookie, "", COOKIE_MAX_AGE, PersoniumUnitConfig.isHttps());
            } else {
                // Cookie?????
                cookies = new NewCookie(cookie, "", -1, PersoniumUnitConfig.isHttps());
            }
        } else {
            cookies = new NewCookie(cookie, "", 0, PersoniumUnitConfig.isHttps());
        }
        return rb.entity("").cookie(cookies).build();
    }

    /**
     * ImplicitFlow??????????????redirect_uri??Redirect?. response_type?? 
     * @param state
     * @return
     * @throws MalformedURLException
     */
    private Response returnErrorRedirect(String redirectUri, String code) {
        // 302????Location?
        ResponseBuilder rb = Response.status(Status.FOUND).type(MediaType.APPLICATION_JSON_TYPE);
        rb.header(HttpHeaders.LOCATION, redirectUri + "?" + OAuth2Helper.Key.CODE + "=" + code);
        // ???
        return rb.entity("").build();
    }

    /**
     * ImplicitFlow??????????????redirect_uri??Redirect?. response_type?? 
     * @param state
     * @return
     * @throws MalformedURLException
     */
    private Response returnErrorRedirect(String redirectUri, String error, String errorDesp, String state,
            String code) {
        // 302????Location?
        ResponseBuilder rb = Response.status(Status.FOUND).type(MediaType.APPLICATION_JSON_TYPE);
        // Location??URL?
        StringBuilder sbuf = new StringBuilder(redirectUri + "#" + OAuth2Helper.Key.ERROR + "=");
        try {
            sbuf.append(URLEncoder.encode(error, "utf-8"));
            sbuf.append("&" + OAuth2Helper.Key.ERROR_DESCRIPTION + "=");
            sbuf.append(URLEncoder.encode(errorDesp, "utf-8"));
            sbuf.append("&" + OAuth2Helper.Key.STATE + "=");
            sbuf.append(URLEncoder.encode(state, "utf-8"));
            sbuf.append("&" + OAuth2Helper.Key.CODE + "=");
            sbuf.append(URLEncoder.encode(code, "utf-8"));
        } catch (UnsupportedEncodingException e) {
            // ??utf-8??????????????????
            log.warn("Failed to URLencode, fragmentInfo of Location header.");
        }
        rb.header(HttpHeaders.LOCATION, sbuf.toString());
        // ???
        return rb.entity("").build();
    }

    /**
     * ImplicitFlow_cookie?????.
     * @param clientId
     * @param redirectUriStr
     * @param state TODO
     * @param massagae
     * @return
     */
    private Response returnErrorMessage(String clientId, String redirectUriStr, String massage, String state,
            String pTarget, String pOwner) {
        ResponseBuilder rb = Response.ok().type(MediaType.TEXT_HTML);
        return rb.entity(this.createForm(clientId, redirectUriStr, massage, state, pTarget, pOwner))
                .header("Content-Type", "text/html; charset=UTF-8").build();
    }

    /**
     * ??? clientId???URL???Box????.
     * @param clientId URL
     * @return true??? false:??
     */
    private boolean checkAuthorization(final String clientId) {
        EntitySetAccessor boxAcceccor = EsModel.box(this.cell);

        // {filter={and={filters=[{term={c=?CellID}}, {term={s.Schema.untouched=?clientID}}]}}}
        Map<String, Object> query1 = new HashMap<String, Object>();
        Map<String, Object> term1 = new HashMap<String, Object>();
        Map<String, Object> query2 = new HashMap<String, Object>();
        Map<String, Object> term2 = new HashMap<String, Object>();
        List<Map<String, Object>> filtersList = new ArrayList<Map<String, Object>>();
        List<Map<String, Object>> queriesList = new ArrayList<Map<String, Object>>();
        Map<String, Object> filters = new HashMap<String, Object>();
        Map<String, Object> and = new HashMap<String, Object>();
        Map<String, Object> filter = new HashMap<String, Object>();

        query1.put("c", this.cell.getId());
        term1.put("term", query1);

        query2.put(OEntityDocHandler.KEY_STATIC_FIELDS + "." + Box.P_SCHEMA.getName() + ".untouched", clientId);
        term2.put("term", query2);

        queriesList.add(term1);
        filtersList.add(term2);

        Map<String, Object> query = QueryMapFactory.filteredQuery(null, QueryMapFactory.mustQuery(queriesList));

        filters.put("filters", filtersList);
        and.put("and", filters);

        filter.put("filter", and);
        filter.put("query", query);

        long count = boxAcceccor.count(filter);

        if (count <= 0) {
            return false;
        }

        return true;
    }

    /**
     * ImplicitFlow???.
     * @param clientId
     * @param redirectUri
     * @param baseUri
     */
    private void checkImplicitParam(String clientId, String redirectUri, URI baseUri) {
        if (redirectUri == null || clientId == null) {
            // TODO ?null??????
            throw PersoniumCoreAuthnException.INVALID_TARGET;
        }

        URL objClientId = null;
        URL objRedirectUri = null;
        try {
            objClientId = new URL(clientId);
        } catch (MalformedURLException e) {
            throw PersoniumCoreException.Auth.REQUEST_PARAM_CLIENTID_INVALID;
        }
        try {
            objRedirectUri = new URL(redirectUri);
        } catch (MalformedURLException e) {
            throw PersoniumCoreException.Auth.REQUEST_PARAM_REDIRECT_INVALID;
        }

        if (redirectUri.contains("\n") || redirectUri.contains("\r")) {
            throw PersoniumCoreException.Auth.REQUEST_PARAM_REDIRECT_INVALID;
        }
        if (clientId.contains("\n") || clientId.contains("\r")) {
            throw PersoniumCoreException.Auth.REQUEST_PARAM_CLIENTID_INVALID;
        }

        // baseurl???
        String bPath = baseUri.getPath();

        // client_id?redirect_uri??baseUri??
        String cPath = objClientId.getPath().substring(bPath.length());
        String rPath = objRedirectUri.getPath().substring(bPath.length());

        // client_id?redirect_uri?/?
        String[] cPaths = StringUtils.split(cPath, "/");
        String[] rPaths = StringUtils.split(rPath, "/");

        // client_id?redirect_uri???????
        // ?URL???
        if (!objClientId.getAuthority().equals(objRedirectUri.getAuthority()) || !cPaths[0].equals(rPaths[0])) {
            throw PersoniumCoreException.Auth.REQUEST_PARAM_REDIRECT_INVALID;
        }

        // client_id???Cell???????????
        if (cPaths[0].equals(this.cell.getName())) {
            throw PersoniumCoreException.Auth.REQUEST_PARAM_CLIENTID_INVALID;
        }

    }

    /**
     * OPTIONS.
     * @return JAX-RS Response
     */
    @OPTIONS
    public Response options() {
        return PersoniumCoreUtils.responseBuilderForOptions(HttpMethod.POST, HttpMethod.GET).build();
    }
}