/**
* 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.common.auth.token;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 本パッケージ内で定義する様々なTokenクラスの基底抽象クラス.
*/
public abstract class AbstractOAuth2Token {
/**
* 一時間あたりのミリ秒数. 3600000
*/
public static final int MILLISECS_IN_AN_HOUR = 3600000;
/**
* 一秒あたりのミリ秒数. 1000
*/
public static final int MILLISECS_IN_A_SEC = 1000;
/**
* 一時間あたりの秒数.
*/
public static final int SECS_IN_A_HOUR = 60 * 60;
/**
* 一日あたり秒数.
*/
public static final int SECS_IN_AN_DAY = 24 * 60 * 60;
/**
* 本パッケージで用いるトークンパース例外クラス.
*/
@SuppressWarnings("serial")
public static class TokenParseException extends Exception {
/**
* コンストラクタ.
* @param msg メッセージ
*/
public TokenParseException(final String msg) {
super(msg);
}
/**
* コンストラクタ.
* @param e 原因 Throwable
*/
public TokenParseException(final Throwable e) {
super(e);
}
/**
* コンストラクタ.
* @param msg メッセージ
* @param e 原因 Throwable
*/
public TokenParseException(final String msg, final Throwable e) {
super(msg, e);
}
}
/**
* 本パッケージで用いる署名検証例外クラス.
*/
@SuppressWarnings("serial")
public static class TokenDsigException extends Exception {
/**
* コンストラクタ.
* @param msg メッセージ
*/
public TokenDsigException(final String msg) {
super(msg);
}
/**
* コンストラクタ.
* @param e 原因 Throwable
*/
public TokenDsigException(final Throwable e) {
super(e);
}
/**
* コンストラクタ.
* @param msg メッセージ
* @param e 原因 Throwable
*/
public TokenDsigException(final String msg, final Throwable e) {
super(msg, e);
}
}
/**
* 本パッケージで用いるルートCA証明書例外クラス.
*/
@SuppressWarnings("serial")
public static class TokenRootCrtException extends Exception {
/**
* コンストラクタ.
* @param msg メッセージ
*/
public TokenRootCrtException(final String msg) {
super(msg);
}
/**
* コンストラクタ.
* @param e 原因 Throwable
*/
public TokenRootCrtException(final Throwable e) {
super(e);
}
/**
* コンストラクタ.
* @param msg メッセージ
* @param e 原因 Throwable
*/
public TokenRootCrtException(final String msg, final Throwable e) {
super(msg, e);
}
}
long issuedAt;
long lifespan;
String issuer;
String subject;
String schema;
List<Role> roleList = new ArrayList<Role>();
/**
* トークンの発行者 CELL URLを返します.
* @return トークンの発行者URL
*/
public final String getIssuer() {
return this.issuer;
}
/**
* トークンが表す Subject (アクセス主体) のURLを返します.
* @return Subject URL
*/
public final String getSubject() {
return this.subject;
}
/**
* スキーマURLを返します.
* @return Schema Url
*/
public final String getSchema() {
return this.schema;
}
/**
* ロールリストを返します.
* @return ロールリスト
*/
public final List<Role> getRoles() {
return this.roleList;
}
final void addRole(final Role role) {
this.roleList.add(role);
}
final String makeRolesString() {
if (this.roleList == null || this.roleList.size() == 0) {
return null;
}
StringBuilder sb = new StringBuilder();
for (Role rl : this.roleList) {
sb.append(rl.createUrl());
sb.append(" ");
}
return sb.substring(0, sb.length() - 1);
}
static List<Role> parseRolesString(final String rolesStr) throws MalformedURLException {
List<Role> ret = new ArrayList<Role>();
if ("".equals(rolesStr)) {
return ret;
}
for (String s : rolesStr.split(" ")) {
ret.add(new Role(new URL(s)));
}
return ret;
}
static final TokenParseException PARSE_EXCEPTION = new TokenParseException("failed to parse token");
/**
* トークン失効までの秒数を返します.
* @return トークン失効までの秒数
*/
public final int expiresIn() {
return SECS_IN_A_HOUR;
}
/**
* トークンが失効しているかどうかチェック.
* @return boolean
*/
public final boolean isExpired() {
long now = new Date().getTime();
// 有効期限のリミット=認証した時刻+有効期限
long expiresLimit = this.issuedAt + this.expiresIn() * MILLISECS_IN_A_SEC;
if (now > expiresLimit) {
return true;
}
return false;
}
/**
* リフレッシュトークン失効までの秒数を返します.
* @return リフレッシュトークン失効までの秒数
*/
public final int refreshExpiresIn() {
return SECS_IN_AN_DAY;
}
/**
* リフレッシュトークンが失効しているかどうかチェック.
* @return boolean
*/
public final boolean isRefreshExpired() {
long now = new Date().getTime();
// 有効期限のリミット=認証した時刻+有効期限
long expiresLimit = this.issuedAt + this.refreshExpiresIn() * MILLISECS_IN_A_SEC;
if (now > expiresLimit) {
return true;
}
return false;
}
/**
* トークン文字列をissuerで指定されたCellとしてパースする.
* @param token Token String
* @param issuer Cell Root URL
* @param host リクエストヘッダHostの値
* @return パースされたCellLocalTokenオブジェクト
* @throws TokenParseException トークンのパースに失敗したときに投げられる例外
* @throws TokenDsigException トークンの署名検証に失敗した時に投げられる例外
* @throws TokenRootCrtException ルートCA証明書の検証に失敗した時に投げられる例外
*/
public static AbstractOAuth2Token parse(final String token, final String issuer, final String host)
throws TokenParseException, TokenDsigException, TokenRootCrtException {
if (token.startsWith(AccountAccessToken.PREFIX_ACCESS)) {
return AccountAccessToken.parse(token, issuer);
} else if (token.startsWith(CellLocalAccessToken.PREFIX_ACCESS)) {
return CellLocalAccessToken.parse(token, issuer);
} else if (token.startsWith(CellLocalRefreshToken.PREFIX_REFRESH)) {
return CellLocalRefreshToken.parse(token, issuer);
} else if (token.startsWith(TransCellRefreshToken.PREFIX_TC_REFRESH)) {
return TransCellRefreshToken.parse(token, issuer);
} else if (token.startsWith(UnitLocalUnitUserToken.PREFIX_UNIT_LOCAL_UNIT_USER)) {
return UnitLocalUnitUserToken.parse(token, host);
} else {
return TransCellAccessToken.parse(token);
}
}
final String toDebugStr() {
Map<String, String> map = new HashMap<String, String>();
map.put("issuedAt", new Date(this.issuedAt).toString());
map.put("expiresAt", new Date(this.issuedAt + this.lifespan).toString());
map.put("issuer", this.issuer);
map.put("subject", this.subject);
map.put("schema", this.schema);
if (this.makeRolesString() != null) {
map.put("roles", this.makeRolesString());
}
return map.toString();
}
}