/**
* Copyright 2005-2014 Restlet
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: Apache 2.0 or LGPL 3.0 or LGPL 2.1 or CDDL 1.0 or EPL
* 1.0 (the "Licenses"). You can select the license that you prefer but you may
* not use this file except in compliance with one of these Licenses.
*
* You can obtain a copy of the Apache 2.0 license at
* http://www.opensource.org/licenses/apache-2.0
*
* You can obtain a copy of the LGPL 3.0 license at
* http://www.opensource.org/licenses/lgpl-3.0
*
* You can obtain a copy of the LGPL 2.1 license at
* http://www.opensource.org/licenses/lgpl-2.1
*
* You can obtain a copy of the CDDL 1.0 license at
* http://www.opensource.org/licenses/cddl1
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://www.restlet.com/products/restlet-framework
*
* Restlet is a registered trademark of Restlet
*/
package org.restlet.ext.oauth;
import org.deviceconnect.android.localoauth.ScopeUtil;
import org.deviceconnect.android.localoauth.temp.RedirectRepresentation;
import org.restlet.ext.oauth.internal.Client;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.restlet.data.Reference;
import org.restlet.ext.oauth.internal.AuthSession;
import org.restlet.ext.oauth.internal.Scope;
import org.restlet.ext.oauth.internal.Scopes;
import org.restlet.representation.EmptyRepresentation;
import org.restlet.representation.Representation;
//import freemarker.template.Configuration;
//import org.restlet.data.CacheDirective;
import org.restlet.ext.oauth.internal.Token;
/**
* Helper class to the AuhorizationResource Handles Authorization requests. By
* default it will accept all scopes requested.
*
* AuhorizationResourceするためのヘルパークラスには、認証要求を処理します。
* デフォルトでは、要求されたすべてのスコープを受け入れます。
*
* To intercept and allow a user to control authorization you should set the
* OAuthHelper.setAuthPageTemplate parameter. It should contain a static HTML
* page or a FreeMarker page that will be loaded with the CLAP protocol straight
* from root.
*
* あなたはOAuthHelper.setAuthPageTemplateパラメータを設定する必要があり、
* 許可を制御するためのユーザをインターセプトできるようにします。
* これは、静的なHTMLページやストレートルートからCLAPプロトコルでロードされます
* FreeMarkerのページが含まれている必要があります。
*
* Example. Add an AuthPageResource to your inbound root.
*
* インバウンドルートにAuthPageResourceを追加します。
*
* <pre>
* {
* @code
* public Restlet createInboundRoot(){
* ...
* root.attach(OAuthHelper.getAuthPage(getContext()), AuthPageServerResource.class);
* //Set Template for AuthPage:
* OAuthHelper.setAuthPageTemplate("authorize.html", getContext());
* //Dont ask for approval if previously approved
* OAuthHelper.setAuthSkipApproved(true, getContext());
* ...
* }
*
* }
* </pre>
*
* The FreeMarker data model looks like the following
*
* FreeMarkerのデータモデルは次のようになります。
*
* <pre>
* {
* @code
* HashMap<String, Object> data = new HashMap<String, Object>();
* data.put("target", "/oauth/auth_page");
* data.put("clientId", clientId);
* data.put("clientDescription", client.toString());
* data.put("clientCallback", client.getRedirectUri());
* data.put("clientName", client.getApplicationName());
* data.put("requestingScopes", scopes);
* data.put("grantedScopes", previousScopes);
* }
* </pre>
*
* Below is an example of a simple FreeMarker page for authorization
*
* 下記の承認のための簡単なFreeMarkerのページの例である
*
* <pre>
* {@code
* <html>
* <head>
* <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
* <link rel="stylesheet" href="resources/style.css" type="text/css" media="screen"
* charset="utf-8">
* <title>OAuth2 Authorization Server</title>
* </head>
* <body>
* <div id="container">
* <div id="header">
* <h2>OAuth authorization page</h2>
* <section id="intro">
* <h2>Application requesting scope</h2>
* <p>Client ClientId = ${clientId} CB = ${clientDescription} wants to get access to your information.</p>
* </section>
* </div>
* <aside>
* <form action="${target}" method="get">
* <h4>The following private info is requested</h4>
*
* <#list requestingScopes as r> <input type="checkbox" name="scope" value="${r}" checked />
* <b>${r}</b><br>
* </#list>
* <#if grantedScopes?has_content>
* <hr />
* <h4>Previously approved scopes</h4>
* <#list grantedScopes as g> <input type="checkbox" name="scope" value="${g}" checked />
* <b>${g}</b><br>
* </#list>
* </#if>
* <br>
* <input type="submit" name="action" value="Reject"/>
* <input type="submit" name="action" value="Accept" />
* </form>
* </aside>
* <footer>
* <p class="copyright">Copyright © 2010 Ericsson Inc. All rights reserved.</p>
* </footer>
* </div>
* </body>
* </html>
* }
* </pre>
*
*
* should be set in the attributes. It should contain a static HTML page or a
* FreeMarker page that will be loaded with the CLAP protocol straight from
* root.
*
* 属性を設定する必要があります。
* これは、静的なHTMLページやストレートルートから拍手プロトコルでロードされます
* FreeMarkerのページが含まれている必要があります。
*
* @author Kristoffer Gronowski
* @author Shotaro Uchida <fantom@xmaker.mx>
*/
public class AuthPageServerResource extends AuthorizationBaseServerResource {
public static final String ACTION_ACCEPT = "Accept";
public static final String ACTION_REJECT = "Reject";
public static final String GRANTED_SCOPE = "granted_scope";
public static final String ACTION = "action";
/**
* Entry point to the AuthPageResource. The AuthorizationResource dispatches
* the call to this method. Should also be invoked by an eventual HTML page
* FORM. In the from HTTP GET should be used and a result parameter: action
* = Accept results in approving requested scope while action = Reject
* results in a rejection error back to the requestor.
*
* AuthPageResourceへのエントリポイント。
* AuthorizationResourceは、このメソッドへの呼び出しをディスパッチします。
* また、最終的なHTMLページ形式で起動する必要があります。
* HTTPからのGETを使用して、結果パラメータれるべきである。
*
* :アクション
* = 要求されたスコープのアクションしばらく承認に結果を受け入れる =
* 戻って要求元に拒否通知エラーで結果を拒否します。
*
* @return HTML page with the graphical policy page
*/
public static Representation showPage() throws OAuthException {
/*
上記htmlを表示、またはsubmitされた タイミングで実行される
*/
String action = getQuery().get("action").get(0);
// Came back after user interacted with the page
if (action != null) { // submitされたときはここを通る
Map<String, ArrayList<String>> query = getQuery();
ArrayList<String> strscopes = query.get("scope");
/* Scope.toString()で変換した文字列配列をScope[]に変換する */
String[] strScopes = strscopes.toArray(new String[0]);
Scope[] scopes = ScopeUtil.stringToScope(strScopes);
/* アプリケーション名を取得 */
String applicationName = null;
ArrayList<String> strApplicationNames = query.get(APPLICATION_NAME);
if (strApplicationNames != null && strApplicationNames.size() > 0) {
applicationName = strApplicationNames.get(0);
}
RedirectRepresentation redirectRepresentation = handleAction(action, scopes, applicationName); // この中でセッションを保存し認可コードを取得する
return redirectRepresentation;
}
return new EmptyRepresentation(); // Will redirect
}
/**
* locationにパラメータをつけてredirectTemporary(location)を実行する。</p>
* FORMの応答を処理するヘルパーメソッド。<br>
* Locationヘッダを307に設定して返します。<br>
* 「トークンの流れは「要求されたか、コードが含まれている場合にはトークンです。<br>
* <br>
*
* Helper method to handle a FORM response. Returns with setting a 307 with
* the location header. Token if the token flow was requested or code is
* included.
*
* @param action
* as interacted by the user.
* @param grantedScope
* the scopes that was approved.
* @param applicationName アプリケーション名
*/
protected static RedirectRepresentation handleAction(String action, Scope[] grantedScope, String applicationName)
throws OAuthException {
AuthSession session = getAuthSession();
session.setGrantedScope(grantedScope);
session.setApplicationName(applicationName);
if (action.equals(ACTION_REJECT)) {
getLogger().fine("Rejected.");
throw new OAuthException(OAuthError.access_denied, "Rejected.",
null);
}
getLogger().fine("Accepting scopes - in handleAction");
Client client = clients.findById(session.getClientId());
String scopeOwner = session.getScopeOwner();
// Create redirection
final Reference location = new Reference(session.getRedirectionURI() // locationに、session.getRedirectionURI()設定。
.getURI());
String state = session.getState();
if (state != null && !state.isEmpty()) {
// Setting state information back.
location.addQueryParameter(STATE, state);
}
// Add query parameters for each flow.
Map<String, Object> options = new HashMap<String, Object>();
ResponseType flow = session.getAuthFlow();
if (flow.equals(ResponseType.token)) {
Token token = tokens
.generateToken(client, scopeOwner, grantedScope, applicationName);
location.addQueryParameter(TOKEN_TYPE, token.getTokenType());
location.addQueryParameter(ACCESS_TOKEN, token.getAccessToken());
Scope[] scopes = token.getScope();
String[] strScopeNames = ScopeUtil.scopeToScopeNames(scopes);
if (!Scopes.isIdentical(strScopeNames, session.getRequestedScope())) {
// OPTIONAL, if identical to the scope requested by the client,
// otherwise REQUIRED. (4.2.2. Access Token Response)
location.addQueryParameter(SCOPE, Scopes.toString(scopes));
}
} else if (flow.equals(ResponseType.code)) { // 認可コードグラントの場合はここを通る
String code = tokens.storeSession(session); // セッションをTokenManager.sessionsに格納して認可コード(セッションに割り当てた番号)を取得する
location.addQueryParameter(CODE, code); // URIに添付する
/* optionsに認可コードを格納して返す */
options.put(CODE, code);
}
// Reset the state
session.setState(null);
/*
* We might don't need to do this. // Sets the no-store Cache-Control
* header addCacheDirective(getResponse(), CacheDirective.noStore()); //
* TODO: Set Pragma: no-cache
*/
if (flow.equals(ResponseType.token)) {
// Use fragment for Implicit Grant
location.setFragment(location.getQuery());
location.setQuery("");
}
RedirectRepresentation redirectRepresentation = new RedirectRepresentation(RedirectRepresentation.RedirectProc.nothing, options);
return redirectRepresentation;
}
}