com.fujitsu.dc.core.rs.cell.AuthzEndPointResource.java Source code

Java tutorial

Introduction

Here is the source code for com.fujitsu.dc.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 com.fujitsu.dc.core.rs.cell;

import static com.fujitsu.dc.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.fujitsu.dc.common.auth.token.AbstractOAuth2Token;
import com.fujitsu.dc.common.auth.token.AbstractOAuth2Token.TokenDsigException;
import com.fujitsu.dc.common.auth.token.AbstractOAuth2Token.TokenParseException;
import com.fujitsu.dc.common.auth.token.AbstractOAuth2Token.TokenRootCrtException;
import com.fujitsu.dc.common.auth.token.AccountAccessToken;
import com.fujitsu.dc.common.auth.token.CellLocalAccessToken;
import com.fujitsu.dc.common.auth.token.CellLocalRefreshToken;
import com.fujitsu.dc.common.auth.token.IAccessToken;
import com.fujitsu.dc.common.auth.token.IExtRoleContainingToken;
import com.fujitsu.dc.common.auth.token.IRefreshToken;
import com.fujitsu.dc.common.auth.token.Role;
import com.fujitsu.dc.common.auth.token.TransCellAccessToken;
import com.fujitsu.dc.common.auth.token.UnitLocalUnitUserToken;
import com.fujitsu.dc.common.utils.DcCoreUtils;
import com.fujitsu.dc.core.DcCoreAuthnException;
import com.fujitsu.dc.core.DcCoreConfig;
import com.fujitsu.dc.core.DcCoreException;
import com.fujitsu.dc.core.DcCoreLog;
import com.fujitsu.dc.core.DcCoreMessageUtils;
import com.fujitsu.dc.core.auth.OAuth2Helper;
import com.fujitsu.dc.core.auth.OAuth2Helper.Key;
import com.fujitsu.dc.core.model.Box;
import com.fujitsu.dc.core.model.Cell;
import com.fujitsu.dc.core.model.DavRsCmp;
import com.fujitsu.dc.core.model.ModelFactory;
import com.fujitsu.dc.core.model.ctl.Account;
import com.fujitsu.dc.core.model.impl.es.EsModel;
import com.fujitsu.dc.core.model.impl.es.QueryMapFactory;
import com.fujitsu.dc.core.model.impl.es.accessor.EntitySetAccessor;
import com.fujitsu.dc.core.model.impl.es.doc.OEntityDocHandler;
import com.fujitsu.dc.core.odata.DcODataProducer;
import com.fujitsu.dc.core.odata.OEntityWrapper;
import com.sun.jersey.api.client.ClientResponse.Status;

/**
 * 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 = DcCoreMessageUtils.getMessage("PS-AU-0002");

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

    /**
     * Cookie??.
     */
    private final String missCookieMsg = DcCoreMessageUtils.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>dc_target?URL?????????CELLTARGET?CELL???transCellToken?</li>
     * </ul>
     * @param authzHeader Authorization 
     * @param dcOwner 
     * @param username 
     * @param password 
     * @param dcTarget 
     * @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 dcOwner, @FormParam(Key.USERNAME) final String username,
            @FormParam(Key.PASSWORD) final String password, @FormParam(Key.TARGET) final String dcTarget,
            @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(dcOwner, username, password, dcTarget, assertion, clientId, responseType, redirectUri, host,
                cookieRefreshToken, keepLogin, state, isCancel, uriInfo);
    }

    private Response auth(final String dcOwner, final String username, final String password, final String dcTarget,
            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????
        // TODO Box?????????????????Box?
        if (!checkAuthorization(normalizedClientId)) {
            log.debug(DcCoreMessageUtils.getMessage("PS-ER-0004"));
            return this.returnErrorRedirect(cell.getUrl() + "__html/error", "PS-ER-0004");
        }

        // clientId?redirectUri?
        try {
            this.checkImplicitParam(normalizedClientId, normalizedRedirectUri, uriInfo.getBaseUri());
        } catch (DcCoreException e) {
            log.debug(e.getMessage());
            if ((username == null && password == null) && (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,
                    DcCoreMessageUtils.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,
                    dcTarget, keepLogin, assertion, schema, state, dcOwner);
        }
    }

    /**
     * ???. <h2>????</h2>
     * <ul>
     * <li>dc_target?URL?????????CELLTARGET?CELL???transCellToken?</li>
     * </ul>
     * @param authzHeader Authorization 
     * @param dcTarget 
     * @param dcOwner 
     * @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 dcTarget, @QueryParam(Key.OWNER) final String dcOwner,
            @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(dcOwner, null, null, dcTarget, assertion, clientId, responseType, redirectUri, host,
                cookieRefreshToken, keepLogin, state, isCancel, uriInfo);

    }

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

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

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

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

        // 
        paramsList.add(DcCoreMessageUtils.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(DcCoreMessageUtils.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 (dcOwner == null) {
            paramsList.add("");
        } else {
            paramsList.add(dcOwner);
        }
        paramsList.add(clientId);
        paramsList.add(redirectUriStr);
        paramsList.add(AuthResourceUtils.getJavascript(jsFileName));

        Object[] params = paramsList.toArray();

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

        return html;
    }

    /**
     * ImplicitFlow???.
     * @param dcTarget
     * @param redirectUriStr
     * @param clientId
     * @param username
     * @param password
     * @param keepLogin
     * @param state
     * @param dcOwner
     * @param host
     * @return
     */
    private Response handleImplicitFlowPassWord(final String dcTarget, final String redirectUriStr,
            final String clientId, final String username, final String password, final String keepLogin,
            final String state, final String dcOwner, 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, dcTarget, dcOwner))
                    .header("Content-Type", "text/html; charset=UTF-8").build();
        }

        OEntityWrapper oew = cell.getAccount(username);
        if (oew == null) {
            String resCode = "PS-AU-0004";
            String missIdPassMsg = DcCoreMessageUtils.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, dcTarget, dcOwner))
                    .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 = DcCoreMessageUtils.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, dcTarget, dcOwner))
                        .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 = DcCoreMessageUtils.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, dcTarget, dcOwner))
                        .header("Content-Type", "text/html; charset=UTF-8").build();
            }
        } catch (DcCoreException 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(dcOwner)) {
            // ???
            if (!this.davRsCmp.checkOwnerRepresentativeAccounts(username)) {
                return returnErrorMessage(clientId, redirectUriStr, passFormMsg, state, dcTarget, dcOwner);
            }
            // ???????????
            if (cell.getOwner() == null) {
                return returnErrorMessage(clientId, redirectUriStr, passFormMsg, state, dcTarget, dcOwner);
            }

            // 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 (dcTarget == null || "".equals(dcTarget)) {
                    // ??
                    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, dcTarget, roleList, schema);
                    return returnSuccessRedirect(redirectUriStr, tcToken.toTokenString(), tcToken.expiresIn(),
                            rToken.toTokenString(), keepLogin, state);
                }
            }
        } catch (MalformedURLException e) {
            return returnErrorMessage(clientId, redirectUriStr, passFormMsg, state, dcTarget, dcOwner);
        }
    }

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

        // ????
        TransCellAccessToken tcToken = null;
        try {
            tcToken = TransCellAccessToken.parse(assertion);
        } catch (TokenParseException e) {
            // 
            DcCoreLog.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) {
            // ???
            DcCoreLog.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?
            DcCoreLog.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 (dcTarget == null || "".equals(dcTarget)) {
            aToken = new CellLocalAccessToken(issuedAt, cell.getUrl(), tcToken.getSubject(), rolesHere,
                    schemaVerified);
        } else {
            aToken = new TransCellAccessToken(UUID.randomUUID().toString(), issuedAt, cell.getUrl(),
                    tcToken.getSubject(), dcTarget, rolesHere, schemaVerified);
        }
        // ????
        // 302????Location?
        try {
            return returnSuccessRedirect(redirectUriStr, aToken.toTokenString(), aToken.expiresIn(), null,
                    keepLogin, state);
        } catch (MalformedURLException e) {
            return returnErrorMessage(clientId, redirectUriStr, passFormMsg, state, dcTarget, "");
        }
    }

    /**
     * ImplicitFlow?cookie??.
     * @param redirectUriStr
     * @param clientId
     * @param host
     * @param cookieRefreshToken
     * @param dcTarget
     * @param keepLogin
     * @return
     */
    private Response handleImplicitFlowcookie(final String redirectUriStr, final String clientId, final String host,
            final String cookieRefreshToken, final String dcTarget, final String keepLogin, final String state,
            final String dcOwner) {
        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, dcTarget, dcOwner);
            }

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

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

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

                // 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, dcTarget, dcOwner);
                }
            } 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, dcTarget, cell.getUrl(), roleList);
                } else {
                    // CELL????????????
                    List<Role> rolesHere = cell.getRoleListHere((IExtRoleContainingToken) rToken);
                    aToken = rToken.refreshAccessToken(issuedAt, dcTarget, cell.getUrl(), rolesHere);
                }
            }

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

    /**
     * ImplicitFlow????.
     * @param redirectUriStr
     * @param clientId
     * @param host
     * @param username
     * @param password
     * @param cookieRefreshToken
     * @param dcTarget
     * @param keepLogin
     * @param assertion
     * @param state
     * @param dcOwner 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 dcTarget,
            final String keepLogin, final String assertion, final String schema, final String state,
            final String dcOwner) {

        // dc_target ?URL?????Injection?????(??????)
        try {
            this.checkDcTarget(dcTarget);
        } catch (DcCoreAuthnException 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(dcTarget, redirectUriStr, clientId, username,
                    password, keepLogin, state, dcOwner, host);

            if (DcCoreConfig.getAccountLastAuthenticatedEnable() && isSuccessAuthorization(response)) {
                // Account???
                DcODataProducer 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, dcTarget, keepLogin, schema,
                    state);
        } else if (cookieRefreshToken != null) {
            // cookie????
            // cookie????keepLogin??true????
            return this.handleImplicitFlowcookie(redirectUriStr, clientId, host, cookieRefreshToken, dcTarget,
                    OAuth2Helper.Key.TRUE_STR, state, dcOwner);
        } else {
            // IDassertioncookie?????
            ResponseBuilder rb = Response.ok().type(MediaType.TEXT_HTML);
            return rb.entity(this.createForm(clientId, redirectUriStr, passFormMsg, state, dcTarget, dcOwner))
                    .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, DcCoreConfig.isHttps());
            } else {
                // Cookie?????
                cookies = new NewCookie(cookie, "", -1, DcCoreConfig.isHttps());
            }
        } else {
            cookies = new NewCookie(cookie, "", 0, DcCoreConfig.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 dcTarget, String dcOwner) {
        ResponseBuilder rb = Response.ok().type(MediaType.TEXT_HTML);
        return rb.entity(this.createForm(clientId, redirectUriStr, massage, state, dcTarget, dcOwner))
                .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 DcCoreAuthnException.INVALID_TARGET;
        }

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

        if ((redirectUri.contains("\n") || redirectUri.contains("\r"))) {
            throw DcCoreException.Auth.REQUEST_PARAM_REDIRECT_INVALID;
        }
        if ((clientId.contains("\n") || clientId.contains("\r"))) {
            throw DcCoreException.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 DcCoreException.Auth.REQUEST_PARAM_REDIRECT_INVALID;
        }

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

    }

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