diff --git a/pom.xml b/pom.xml index c6c372d..14493e8 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ io.personium personium-lib-common jar - 1.5.1-SNAPSHOT + 1.5.1 The Apache Software License, Version 2.0 diff --git a/src/main/java/io/personium/common/auth/token/AbstractLocalAccessToken.java b/src/main/java/io/personium/common/auth/token/AbstractLocalAccessToken.java index d553e97..e1195cc 100644 --- a/src/main/java/io/personium/common/auth/token/AbstractLocalAccessToken.java +++ b/src/main/java/io/personium/common/auth/token/AbstractLocalAccessToken.java @@ -54,8 +54,6 @@ public String getCookieString(String peer, String issuer) { return AbstractLocalAccessToken.encode(raw, AbstractLocalAccessToken.getIvBytes(issuer)); } - public String[] getScopes() { - return this.scope; - } + } diff --git a/src/main/java/io/personium/common/auth/token/IAccessToken.java b/src/main/java/io/personium/common/auth/token/IAccessToken.java index de55dbf..c097526 100644 --- a/src/main/java/io/personium/common/auth/token/IAccessToken.java +++ b/src/main/java/io/personium/common/auth/token/IAccessToken.java @@ -48,7 +48,7 @@ public interface IAccessToken { * returns the scopes of access token. * @return array of scope strings */ - String[] getScopes(); + String[] getScope(); /** * constructs token string. diff --git a/src/main/java/io/personium/common/auth/token/PasswordChangeAccessToken.java b/src/main/java/io/personium/common/auth/token/PasswordChangeAccessToken.java index c916640..888e17d 100644 --- a/src/main/java/io/personium/common/auth/token/PasswordChangeAccessToken.java +++ b/src/main/java/io/personium/common/auth/token/PasswordChangeAccessToken.java @@ -41,8 +41,8 @@ public final class PasswordChangeAccessToken extends AbstractLocalAccessToken im * @param schema Schema */ public PasswordChangeAccessToken(final long issuedAt, final long lifespan, final String issuer, - final String subject, final String schema) { - super(issuedAt, lifespan, issuer, subject, schema, AbstractOAuth2Token.Scope.EMPTY); + final String subject, final String schema, final String[] scope) { + super(issuedAt, lifespan, issuer, subject, schema, scope); } /** @@ -55,8 +55,8 @@ public PasswordChangeAccessToken(final long issuedAt, final long lifespan, final * @param schema Schema */ public PasswordChangeAccessToken(final long issuedAt, final String issuer, final String subject, - final String schema) { - this(issuedAt, ACCESS_TOKEN_EXPIRES_MILLISECS, issuer, subject, schema); + final String schema, final String[] scope) { + this(issuedAt, ACCESS_TOKEN_EXPIRES_MILLISECS, issuer, subject, schema, scope); } public PasswordChangeAccessToken() { diff --git a/src/main/java/io/personium/common/auth/token/ResidentRefreshToken.java b/src/main/java/io/personium/common/auth/token/ResidentRefreshToken.java index 84d45d5..283d54e 100644 --- a/src/main/java/io/personium/common/auth/token/ResidentRefreshToken.java +++ b/src/main/java/io/personium/common/auth/token/ResidentRefreshToken.java @@ -151,7 +151,7 @@ public IAccessToken refreshAccessToken(final long issuedAt, final long lifespan, } else { // 自分セルローカル払い出し時に払い出されるリフレッシュトークンにはロール入ってないので取得する。 return new TransCellAccessToken(issuedAt, lifespan, this.issuer, cellUrl + "#" + this.getSubject(), - target, roleList, schema); + target, roleList, schema, scope); } } diff --git a/src/main/java/io/personium/common/auth/token/Role.java b/src/main/java/io/personium/common/auth/token/Role.java index 46ce117..a30dca3 100644 --- a/src/main/java/io/personium/common/auth/token/Role.java +++ b/src/main/java/io/personium/common/auth/token/Role.java @@ -18,6 +18,7 @@ import java.net.MalformedURLException; import java.net.URL; +import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -66,7 +67,7 @@ public Role(URL url) throws MalformedURLException { } /** - * コンストラクタ. + * Constructor. * @param name ロール名. * @param boxName ロールの属するボックス名. * @param boxSchema ロールの属するボックスのSchema @@ -86,6 +87,16 @@ public Role(final String name, final String boxName, final String boxSchema, fin public Role(final String name) { this(name, null, null, null); } + @Override + public boolean equals(Object obj) { + boolean ret = obj instanceof Role; + Role r = (Role) obj; + ret &= Objects.equals(this.name, r.name); + ret &= Objects.equals(this.boxSchema, r.boxSchema); + ret &= Objects.equals(this.boxName, r.boxName); + ret &= Objects.equals(this.baseUrl, r.baseUrl); + return ret; + } /** * スキーマ用ロールリソースのURLを返す. @@ -98,21 +109,21 @@ public String schemeCreateUrl(String url) { if (this.boxName != null) { boxName2 = this.boxName; } else { - // 紐付かない場合、デフォルトボックス名を使用する - boxName2 = DEFAULT_BOX_NAME; + // 紐付かない場合、use main box name. + boxName2 = MAIN_BOX_NAME; } String url3 = createBaseUrl(url); return String.format(ROLE_RESOURCE_FORMAT, url3, boxName2, this.name); } /** - * ロールクラスURLを返す. + * Returns Role class URL. * @param url ロールリソースのベースURL - * @return String ロールリソースのURL + * @return String Role resource URL */ public String schemeCreateUrlForTranceCellToken(String url) { String url3 = createBaseUrl(url); - return String.format(ROLE_RESOURCE_FORMAT, url3, DEFAULT_BOX_NAME, this.name); + return String.format(ROLE_RESOURCE_FORMAT, url3, MAIN_BOX_NAME, this.name); } /** @@ -147,7 +158,7 @@ public String localCreateUrl(String url) { boxName2 = this.boxName; } else { // 紐付かない場合、デフォルトボックス名を使用する - boxName2 = DEFAULT_BOX_NAME; + boxName2 = MAIN_BOX_NAME; } // 連結でスラッシュつけてるので、URLの最後がスラッシュだったら消す。 String url3 = url.replaceFirst("/$", ""); @@ -205,6 +216,6 @@ public String getBaseUrl() { /** * デフォルトボックス名. */ - public static final String DEFAULT_BOX_NAME = "__"; + public static final String MAIN_BOX_NAME = "__"; } diff --git a/src/main/java/io/personium/common/auth/token/TransCellAccessToken.java b/src/main/java/io/personium/common/auth/token/TransCellAccessToken.java index b37b809..9c4aa40 100644 --- a/src/main/java/io/personium/common/auth/token/TransCellAccessToken.java +++ b/src/main/java/io/personium/common/auth/token/TransCellAccessToken.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; import java.net.URL; import java.security.InvalidAlgorithmParameterException; import java.security.KeyFactory; @@ -33,8 +34,10 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Date; +import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Set; import java.util.UUID; import javax.naming.InvalidNameException; @@ -66,7 +69,7 @@ import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -77,12 +80,11 @@ import net.oauth.signature.pem.PKCS1EncodedKeySpec; /** - * TransCellのAccessTokenを扱うclass. + * Class for handling Trans-Cell access token. */ @SuppressWarnings({ "unchecked", "rawtypes" }) public final class TransCellAccessToken extends AbstractOAuth2Token implements IAccessToken, IExtRoleContainingToken { - private SignedInfo signedInfo; private static final String URN_OASIS_NAMES_TC_SAML_2_0_ASSERTION = "urn:oasis:names:tc:SAML:2.0:assertion"; @@ -90,15 +92,49 @@ public final class TransCellAccessToken extends AbstractOAuth2Token implements I * log. */ static Logger log = LoggerFactory.getLogger(TransCellAccessToken.class); - - String id; - String target; - private static List x509RootCertificateFileNames; private static XMLSignatureFactory xmlSignatureFactory; private static X509Certificate x509Certificate; private static KeyInfo keyInfo; private static PrivateKey privKey; + private SignedInfo signedInfo; + public static SignedInfo createSignedInfo() { + try { + /* + * creates the Reference object, which identifies the data that will be digested and signed. The Reference + * object is assembled by creating and passing as parameters each of its components: the URI, the + * DigestMethod, and a list of Transforms + */ + DigestMethod digestMethod = xmlSignatureFactory.newDigestMethod(DigestMethod.SHA1, null); + Transform transform = xmlSignatureFactory.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null); + Reference reference = xmlSignatureFactory.newReference("", digestMethod, + Collections.singletonList(transform), null, null); + + /* + * creates the SignedInfo object that the signature is calculated over. Like the Reference object, the + * SignedInfo object is assembled by creating and passing as parameters each of its components: the + * CanonicalizationMethod, the SignatureMethod, and a list of References + */ + CanonicalizationMethod c14nMethod = xmlSignatureFactory.newCanonicalizationMethod( + CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null); + SignatureMethod signatureMethod = xmlSignatureFactory.newSignatureMethod(SignatureMethod.RSA_SHA1, null); + return xmlSignatureFactory.newSignedInfo(c14nMethod, signatureMethod, + Collections.singletonList(reference)); + + } catch (NoSuchAlgorithmException e) { + // 重大な異常なので非チェックにして上に上げる + throw new RuntimeException(e); + } catch (InvalidAlgorithmParameterException e) { + // 重大な異常なので非チェックにして上に上げる + throw new RuntimeException(e); + } + + + } + + String id; + String target; + /** * Constructor. @@ -118,7 +154,8 @@ public TransCellAccessToken(final String id, final String subject, final String target, final List roleList, - final String schema) { + final String schema, + final String[] scope) { this.issuedAt = issuedAt; this.lifespan = lifespan; this.id = id; @@ -127,35 +164,10 @@ public TransCellAccessToken(final String id, this.target = target; this.roleList = roleList; this.schema = schema; + this.scope = scope; - try { - /* - * creates the Reference object, which identifies the data that will be digested and signed. The Reference - * object is assembled by creating and passing as parameters each of its components: the URI, the - * DigestMethod, and a list of Transforms - */ - DigestMethod digestMethod = xmlSignatureFactory.newDigestMethod(DigestMethod.SHA1, null); - Transform transform = xmlSignatureFactory.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null); - Reference reference = xmlSignatureFactory.newReference("", digestMethod, - Collections.singletonList(transform), null, null); + this.signedInfo = createSignedInfo(); - /* - * creates the SignedInfo object that the signature is calculated over. Like the Reference object, the - * SignedInfo object is assembled by creating and passing as parameters each of its components: the - * CanonicalizationMethod, the SignatureMethod, and a list of References - */ - CanonicalizationMethod c14nMethod = xmlSignatureFactory.newCanonicalizationMethod( - CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null); - SignatureMethod signatureMethod = xmlSignatureFactory.newSignatureMethod(SignatureMethod.RSA_SHA1, null); - signedInfo = xmlSignatureFactory.newSignedInfo(c14nMethod, signatureMethod, - Collections.singletonList(reference)); - } catch (NoSuchAlgorithmException e) { - // 重大な異常なので非チェックにして上に上げる - throw new RuntimeException(e); - } catch (InvalidAlgorithmParameterException e) { - // 重大な異常なので非チェックにして上に上げる - throw new RuntimeException(e); - } } @@ -175,8 +187,9 @@ public TransCellAccessToken(final String id, final String subject, final String target, final List roleList, - final String schema) { - this(id, issuedAt, ACCESS_TOKEN_EXPIRES_MILLISECS, issuer, subject, target, roleList, schema); + final String schema, + final String[] scope) { + this(id, issuedAt, ACCESS_TOKEN_EXPIRES_MILLISECS, issuer, subject, target, roleList, schema, scope); } /** @@ -192,8 +205,9 @@ public TransCellAccessToken( final String subject, final String target, final List roleList, - final String schema) { - this(UUID.randomUUID().toString(), new Date().getTime(), issuer, subject, target, roleList, schema); + final String schema, + final String[] scope) { + this(UUID.randomUUID().toString(), new Date().getTime(), issuer, subject, target, roleList, schema, scope); } /** @@ -211,8 +225,9 @@ public TransCellAccessToken( final String subject, final String target, final List roleList, - final String schema) { - this(UUID.randomUUID().toString(), issuedAt, issuer, subject, target, roleList, schema); + final String schema, + final String[] scope) { + this(UUID.randomUUID().toString(), issuedAt, issuer, subject, target, roleList, schema, scope); } /** @@ -232,8 +247,9 @@ public TransCellAccessToken( final String subject, final String target, final List roleList, - final String schema) { - this(UUID.randomUUID().toString(), issuedAt, lifespan, issuer, subject, target, roleList, schema); + final String schema, + final String[] scope) { + this(UUID.randomUUID().toString(), issuedAt, lifespan, issuer, subject, target, roleList, schema, scope); } /* (non-Javadoc) @@ -295,8 +311,10 @@ public String toSamlString() { Element nameId = doc.createElement("NameID"); nameId.setTextContent(this.subject); Element subjectConfirmation = doc.createElement("SubjectConfirmation"); + subjectConfirmation.setAttribute("Method", "urn:oasis:names:tc:SAML:2.0:cm:bearer"); Element subjectConfirmationData = doc.createElement("SubjectConfirmationData"); subjectConfirmationData.setAttribute("NotOnOrAfter", notOnOrAfterDateTime.toString()); + subjectConfirmationData.setAttribute("Recipient", this.target + "__token"); subjectConfirmation.appendChild(subjectConfirmationData); subject.appendChild(nameId); subject.appendChild(subjectConfirmation); @@ -325,19 +343,45 @@ public String toSamlString() { // AttributeStatement Element attrStmt = doc.createElement("AttributeStatement"); - Element attribute = doc.createElement("Attribute"); - for (Role role : this.roleList) { - Element attrValue = doc.createElement("AttributeValue"); - Attr attr = doc.createAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "type"); - attr.setPrefix("xsi"); - attr.setValue("string"); - attrValue.setAttributeNodeNS(attr); - attrValue.setTextContent(role.schemeCreateUrlForTranceCellToken(this.issuer)); - attribute.appendChild(attrValue); + // this fails + //attrStmt.setAttribute("xmlns:xsi", CommonUtils.XmlConst.NS_XML_SCHEMA_INSTANCE); + + // -- Roles + Element attributeRoles = doc.createElement("Attribute"); + attributeRoles.setAttribute("Name", "Roles"); + attributeRoles.setAttribute("NameFormat", CommonUtils.XmlConst.NS_PERSONIUM); + if (this.roleList != null) { + for (Role role : this.roleList) { + Element attrValue = doc.createElement("AttributeValue"); + //Attr attr = doc.createAttributeNS(CommonUtils.XmlConst.NS_XML_SCHEMA_INSTANCE, "type"); + //attr.setPrefix("xsi"); + //attr.setValue("string"); + //attrValue.setAttributeNodeNS(attr); + attrValue.setTextContent(role.schemeCreateUrlForTranceCellToken(this.issuer)); + attributeRoles.appendChild(attrValue); + } + } + attrStmt.appendChild(attributeRoles); + + // -- Scopes + Element attributeScopes = doc.createElement("Attribute"); + attributeScopes.setAttribute("Name", "Scopes"); + attributeRoles.setAttribute("NameFormat", CommonUtils.XmlConst.NS_PERSONIUM); + if (this.getScope() != null) { + for (String scope : this.getScope()) { + Element attrValue = doc.createElement("AttributeValue"); + //Attr attr = doc.createAttributeNS(CommonUtils.XmlConst.NS_XML_SCHEMA_INSTANCE, "type"); + //attr.setPrefix("xsi"); + //attr.setValue("string"); + //attrValue.setAttributeNodeNS(attr); + attrValue.setTextContent(scope); + attributeScopes.appendChild(attrValue); + } } - attrStmt.appendChild(attribute); + attrStmt.appendChild(attributeScopes); assertion.appendChild(attrStmt); + // Normalization を実施 doc.normalizeDocument(); @@ -429,12 +473,20 @@ public static TransCellAccessToken parse(final String token) throws AbstractOAut } List roles = new ArrayList(); - NodeList attrList = assertion.getElementsByTagName("AttributeValue"); - for (int i = 0; i < attrList.getLength(); i++) { - Element attv = (Element) (attrList.item(i)); - roles.add(new Role(new URL(attv.getTextContent()))); + Set scopes = new HashSet<>(); + + NodeList attributeList = assertion.getElementsByTagName("Attribute"); + for (int i = 0; i < attributeList.getLength(); i++) { + Element attrElem = (Element) (attributeList.item(i)); + String attrName = attrElem.getAttribute("Name"); + if (attrName == null || "Roles".equals(attrName)) { + roles = parseRoles(attrElem); + } else if ("Scopes".equals(attrName)) { + scopes = parseScopes(attrElem); + } } + NodeList nl = assertion.getElementsByTagName("Signature"); if (nl.getLength() == 0) { throw new TokenParseException("Cannot find Signature element"); @@ -506,7 +558,7 @@ public static TransCellAccessToken parse(final String token) throws AbstractOAut throw new TokenDsigException("Signature failed core validation. unkwnon reason."); } return new TransCellAccessToken(id, dt.getMillis(), lifespan, issuer.getTextContent(), - subjectNameID.getTextContent(), target, roles, schema); + subjectNameID.getTextContent(), target, roles, schema, scopes.toArray(new String[0])); } catch (UnsupportedEncodingException e) { throw new TokenParseException(e.getMessage(), e); } catch (SAXException e) { @@ -515,6 +567,26 @@ public static TransCellAccessToken parse(final String token) throws AbstractOAut throw new TokenParseException(e.getMessage(), e); } } + private static List parseRoles(Element e) throws MalformedURLException, DOMException { + List ret = new ArrayList<>(); + NodeList attrList = e.getElementsByTagName("AttributeValue"); + for (int i = 0; i < attrList.getLength(); i++) { + Element attv = (Element) (attrList.item(i)); + ret.add(new Role(new URL(attv.getTextContent()))); + } + + return ret; + } + private static Set parseScopes(Element e) { + Set ret = new HashSet<>(); + NodeList attrList = e.getElementsByTagName("AttributeValue"); + for (int i = 0; i < attrList.getLength(); i++) { + Element attv = (Element) (attrList.item(i)); + ret.add(attv.getTextContent()); + } + return ret; + } + @Override public String getTarget() { @@ -621,8 +693,8 @@ public String getCookieString(String cookiePeer, String issuer) { } @Override - public String[] getScopes() { - return null; + public String[] getScope() { + return this.scope; } } diff --git a/src/main/java/io/personium/common/auth/token/VisitorLocalAccessToken.java b/src/main/java/io/personium/common/auth/token/VisitorLocalAccessToken.java index 7d2603d..6d3ccca 100644 --- a/src/main/java/io/personium/common/auth/token/VisitorLocalAccessToken.java +++ b/src/main/java/io/personium/common/auth/token/VisitorLocalAccessToken.java @@ -19,12 +19,11 @@ import java.net.MalformedURLException; import java.util.List; -import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * Cell Local Token の生成・パースを行うクラス. + * Class for creating and parsing Visitor Local Access Token. */ public class VisitorLocalAccessToken extends AbstractLocalAccessToken implements IAccessToken, IExtRoleContainingToken { @@ -73,52 +72,6 @@ public VisitorLocalAccessToken(final long issuedAt, } } - /** - * 明示的な有効期間を設定してトークンを生成する. - * @param issuedAt 発行時刻(epochからのミリ秒) - * @param lifespan トークンの有効時間(ミリ秒) - * @param issuer 発行 Cell URL - * @param subject アクセス主体URL - * @param roleList ロールリスト - * @param schema クライアント認証されたデータスキーマ - */ - public VisitorLocalAccessToken(final long issuedAt, - final long lifespan, - final String issuer, - final String subject, - final List roleList, - final String schema) { - this(issuedAt, lifespan, issuer, subject, roleList, schema, null); - } - - /** - * 既定値の有効期間を設定してトークンを生成する. - * @param issuedAt 発行時刻(epochからのミリ秒) - * @param issuer 発行 Cell URL - * @param subject アクセス主体URL - * @param roleList ロールリスト - * @param schema クライアント認証されたデータスキーマ - */ - public VisitorLocalAccessToken( - final long issuedAt, - final String issuer, - final String subject, - final List roleList, - final String schema) { - this(issuedAt, ACCESS_TOKEN_EXPIRES_MILLISECS, issuer, subject, roleList, schema); - } - - /** - * 既定値の有効期間と現在を発行日時と設定してトークンを生成する. - * @param issuer 発行 Cell URL - * @param subject アクセス主体URL - * @param roleList ロールリスト - * @param schema クライアント認証されたデータスキーマ - */ - public VisitorLocalAccessToken(final String issuer, final String subject, - final List roleList, final String schema) { - this(new DateTime().getMillis(), issuer, subject, roleList, schema); - } @Override public String toTokenString() { diff --git a/src/main/java/io/personium/common/auth/token/VisitorRefreshToken.java b/src/main/java/io/personium/common/auth/token/VisitorRefreshToken.java index 8be4954..d96388c 100644 --- a/src/main/java/io/personium/common/auth/token/VisitorRefreshToken.java +++ b/src/main/java/io/personium/common/auth/token/VisitorRefreshToken.java @@ -81,9 +81,9 @@ public VisitorRefreshToken( final String subject, final String origIssuer, final List origRoleList, - final String schema) { - // TODO Scope null? - super(issuedAt, lifespan, issuer, subject, schema, null); + final String schema, + final String[] scope) { + super(issuedAt, lifespan, issuer, subject, schema, scope); this.id = id; this.originalIssuer = origIssuer; this.roleList = origRoleList; @@ -106,8 +106,10 @@ public VisitorRefreshToken( final String subject, final String origIssuer, final List origRoleList, - final String schema) { - this(id, issuedAt, REFRESH_TOKEN_EXPIRES_MILLISECS, issuer, subject, origIssuer, origRoleList, schema); + final String schema, + final String[] scope) { + this(id, issuedAt, REFRESH_TOKEN_EXPIRES_MILLISECS, + issuer, subject, origIssuer, origRoleList, schema, scope); } /** @@ -125,8 +127,9 @@ public VisitorRefreshToken( final String subject, final String origIssuer, final List origRoleList, - final String schema) { - this(id, new DateTime().getMillis(), issuer, subject, origIssuer, origRoleList, schema); + final String schema, + final String[] scope) { + this(id, new DateTime().getMillis(), issuer, subject, origIssuer, origRoleList, schema, scope); } @Override @@ -185,9 +188,9 @@ public IAccessToken refreshAccessToken(final long issuedAt, final String target, public IAccessToken refreshAccessToken(final long issuedAt, final long lifespan, final String target, String url, List role) { if (target == null) { - return new VisitorLocalAccessToken(issuedAt, lifespan, url, this.getSubject(), role, schema); + return new VisitorLocalAccessToken(issuedAt, lifespan, url, this.getSubject(), role, schema, scope); } else { - return new TransCellAccessToken(issuedAt, lifespan, url, this.getSubject(), target, role, schema); + return new TransCellAccessToken(issuedAt, lifespan, url, this.getSubject(), target, role, schema, scope); } } @@ -207,7 +210,7 @@ public IRefreshToken refreshRefreshToken(final long issuedAt) { public IRefreshToken refreshRefreshToken(final long issuedAt, final long lifespan) { // TODO 本当は ROLEは再度読み直すべき。 return new VisitorRefreshToken(UUID.randomUUID().toString(), issuedAt, lifespan, this.issuer, this.subject, - this.originalIssuer, this.getRoles(), this.schema); + this.originalIssuer, this.getRoles(), this.schema, this.scope); } diff --git a/src/main/java/io/personium/common/auth/token/X509KeySelector.java b/src/main/java/io/personium/common/auth/token/X509KeySelector.java index 876a98f..82e9b73 100644 --- a/src/main/java/io/personium/common/auth/token/X509KeySelector.java +++ b/src/main/java/io/personium/common/auth/token/X509KeySelector.java @@ -169,7 +169,7 @@ private void cheakX509validate(X509Certificate certificate) throws KeySelectorEx // support per-cell. It changed from exact match to backward match. if (cnStr == null || !issureUrl.getHost().endsWith(cnStr)) { // トークンとルートCA証明書のissureが等しくない時 - throw new KeySelectorException("issure not equals."); + throw new KeySelectorException("Issuer does not match."); } // サーバ証明書の検証 @@ -244,7 +244,7 @@ private void readCaFile(InputStream is) throws IOException, CertificateException x509Root.checkValidity(); // ルートCA証明書の重複チェック if (caCerts.get(x509Root.getIssuerX500Principal().getName()) != null) { - throw new CertificateException("ca subject name already use."); + throw new CertificateException("Duplicated ca subject names."); } caCerts.put(x509Root.getIssuerX500Principal().getName(), x509Root); } diff --git a/src/main/java/io/personium/common/utils/CommonUtils.java b/src/main/java/io/personium/common/utils/CommonUtils.java index b291685..40b24a2 100644 --- a/src/main/java/io/personium/common/utils/CommonUtils.java +++ b/src/main/java/io/personium/common/utils/CommonUtils.java @@ -187,6 +187,8 @@ public static class XmlConst { public static final String NS_PERSONIUM = "urn:x-personium:xmlns"; /** XML Name Space p:. */ public static final String NS_PREFIX_PERSONIUM = "p"; + /** http://www.w3.org/2001/XMLSchema-instance. */ + public static final String NS_XML_SCHEMA_INSTANCE = "http://www.w3.org/2001/XMLSchema-instance"; /** service. */ public static final String SERVICE = "service"; diff --git a/src/test/java/io/personium/common/auth/token/TokenTest.java b/src/test/java/io/personium/common/auth/token/TokenTest.java index 702763f..7f7a80d 100644 --- a/src/test/java/io/personium/common/auth/token/TokenTest.java +++ b/src/test/java/io/personium/common/auth/token/TokenTest.java @@ -113,7 +113,7 @@ public void testVisitorRefreshToken() throws MalformedURLException { String id = "1234"; VisitorRefreshToken token = new VisitorRefreshToken(id, "http://receiver.com/rcv", - "http://orig.com/orig/#subj", "http://orig.com/orig", roleList, "http://schema.com/schema"); + "http://orig.com/orig/#subj", "http://orig.com/orig", roleList, "http://schema.com/schema", null); String tokenStr = token.toTokenString(); VisitorRefreshToken token2 = null; @@ -144,7 +144,7 @@ public void testTransCellAccessToken() throws TokenParseException, TokenDsigExce roleList.add(new Role("doctor")); TransCellAccessToken tcToken = new TransCellAccessToken(cellRootUrl, cellRootUrl + "#admin", target, roleList, - schema); + schema, new String[] {"someScope"}); String token = tcToken.toTokenString(); @@ -175,8 +175,11 @@ public void testCellLocalAccessToken() throws MalformedURLException, TokenParseE roleList.add(new Role(new URL(base + "staff"))); roleList.add(new Role(new URL(base + "doctor"))); - VisitorLocalAccessToken token = new VisitorLocalAccessToken("http://hogte.com/", "http://hige.com", roleList, - "http://example.com/schema"); + VisitorLocalAccessToken token = new VisitorLocalAccessToken( + new Date().getTime(), + VisitorLocalAccessToken.ACCESS_TOKEN_EXPIRES_MILLISECS, + "http://hogte.com/", "http://hige.com", roleList, + "http://example.com/schema", new String[] {"someScope"}); String tokenStr = token.toTokenString(); diff --git a/src/test/java/io/personium/common/auth/token/TransCellAccessTokenTest.java b/src/test/java/io/personium/common/auth/token/TransCellAccessTokenTest.java new file mode 100644 index 0000000..340f8a2 --- /dev/null +++ b/src/test/java/io/personium/common/auth/token/TransCellAccessTokenTest.java @@ -0,0 +1,111 @@ +package io.personium.common.auth.token; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.spec.InvalidKeySpecException; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.naming.InvalidNameException; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import io.personium.common.auth.token.AbstractOAuth2Token.TokenDsigException; +import io.personium.common.auth.token.AbstractOAuth2Token.TokenParseException; +import io.personium.common.auth.token.AbstractOAuth2Token.TokenRootCrtException; + +public class TransCellAccessTokenTest { + static final String ISSUER = "https://issuer.localhost/"; + static final String SUBJECT = "https://subject.localhost/#acc"; + static String TARGET = "https://target.localhost/"; + static String SCHEMA = "https://schema.localhost/"; + static String[] SCOPE = new String[] {"auth", "message-read"}; + static List ROLE_LIST = new ArrayList<>(); + static Set SCOPE_SET = new HashSet<>(); + static { + try { + ROLE_LIST.add(new Role(new URL("https://schema.localhost/__role/__/role1"))); + ROLE_LIST.add(new Role(new URL("https://schema.localhost/__role/__/role2"))); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + } + + TransCellAccessToken token; + @Before + public void setUp() throws Exception { + String keyPath = ClassLoader.getSystemResource("x509/localhost.key").getPath(); + String crtPath = ClassLoader.getSystemResource("x509/localhost.crt").getPath(); + String cacPath = ClassLoader.getSystemResource("x509/personium_ca.crt").getPath(); + //URL r = c.getResource("x509/localhost.key"); + try { + + TransCellAccessToken.configureX509(keyPath, crtPath, new String[] {cacPath}); + } catch (NoSuchAlgorithmException | InvalidKeySpecException | CertificateException | InvalidNameException + | IOException e) { + e.printStackTrace(); + } + this.token = new TransCellAccessToken(new Date().getTime(), + AbstractOAuth2Token.ACCESS_TOKEN_EXPIRES_MILLISECS, + ISSUER, + SUBJECT, + TARGET, + ROLE_LIST, + SCHEMA, SCOPE); + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testParse_issuer_subject_schema() throws TokenParseException, TokenDsigException, TokenRootCrtException { + String tokenStr = this.token.toTokenString(); + TransCellAccessToken token2 = TransCellAccessToken.parse(tokenStr); + assertEquals(ISSUER, token2.getIssuer()); + assertEquals(SUBJECT, token2.getSubject()); + assertEquals(SCHEMA, token2.getSchema()); + } + @Test + public void testParse_scopes() throws TokenParseException, TokenDsigException, TokenRootCrtException { + String tokenStr = this.token.toTokenString(); + TransCellAccessToken token2 = TransCellAccessToken.parse(tokenStr); + assertEquals(SCOPE.length, token2.getScope().length); + } + + @Test + public void testParse_roles() throws TokenParseException, TokenDsigException, TokenRootCrtException { + String tokenStr = this.token.toTokenString(); + TransCellAccessToken token2 = TransCellAccessToken.parse(tokenStr); + List parsedRoles = token2.getRoleList(); + assertEquals(ROLE_LIST.size(), parsedRoles.size()); + StringBuilder sb1 = new StringBuilder(); + for (Role role : ROLE_LIST) { + sb1.append(role.getBoxSchema() + ":" +role.getName()); + sb1.append(" "); + } + StringBuilder sb2 = new StringBuilder(); + for (Role role : parsedRoles) { + sb2.append(role.getBoxSchema() + ":" +role.getName()); + sb2.append(" "); + } + assertEquals(sb1.toString(), sb2.toString()); + } + + @Test + public void print() throws TokenParseException, TokenDsigException, TokenRootCrtException { + System.out.println(this.token.toSamlString()); + } + + +} diff --git a/src/test/java/io/personium/common/auth/token/VisitorRefreshTokenTest.java b/src/test/java/io/personium/common/auth/token/VisitorRefreshTokenTest.java index f271612..a379fd7 100644 --- a/src/test/java/io/personium/common/auth/token/VisitorRefreshTokenTest.java +++ b/src/test/java/io/personium/common/auth/token/VisitorRefreshTokenTest.java @@ -48,7 +48,7 @@ public class VisitorRefreshTokenTest { */ @Before public void befor() { - transCellRefreshToken = PowerMockito.spy(new VisitorRefreshToken(null, null, null, null, null, null)); + transCellRefreshToken = PowerMockito.spy(new VisitorRefreshToken(null, null, null, null, null, null, null)); } /** @@ -106,7 +106,7 @@ public void refreshAccessToken_Normal() { @Test public void refreshAccessToken_Normal_schema_is_null_target_is_null() { transCellRefreshToken = PowerMockito.spy(new VisitorRefreshToken( - null, null, "https://personium/subject/", null, null, "https://personium/schema/")); + null, null, "https://personium/subject/", null, null, "https://personium/schema/", null)); // -------------------- // Test method args // -------------------- @@ -170,7 +170,7 @@ public void refreshAccessToken_Normal_schema_not_null_target_not_null() throws E String schema = "https://personium/appcell/"; transCellRefreshToken = PowerMockito.spy(new VisitorRefreshToken( - null, null, subject, null, null, schema)); + null, null, subject, null, null, schema, null)); // X509 settings. String folderPath = "x509/effective/"; diff --git a/src/test/java/io/personium/common/auth/token/X509KeySelecterTest.java b/src/test/java/io/personium/common/auth/token/X509KeySelecterTest.java index 35511b5..06bb683 100644 --- a/src/test/java/io/personium/common/auth/token/X509KeySelecterTest.java +++ b/src/test/java/io/personium/common/auth/token/X509KeySelecterTest.java @@ -79,7 +79,7 @@ public static void beforeClass() { // トランスセルトークンの生成 TransCellAccessToken tcToken = new TransCellAccessToken("https://localhost/X509TestCell/", cellRootUrl - + "#admin", target, roleList, schema); + + "#admin", target, roleList, schema, new String[] {"scope"}); String token = tcToken.toTokenString(); try { @@ -105,7 +105,7 @@ public static void beforeClass() { } TransCellAccessToken tcToken = new TransCellAccessToken("https://localhost/X509TestCell/", cellRootUrl - + "#admin", target, roleList, schema); + + "#admin", target, roleList, schema, new String[] {"scope"}); String token = tcToken.toTokenString(); try { @@ -130,7 +130,7 @@ public static void beforeClass() { } TransCellAccessToken tcToken = new TransCellAccessToken("https://localhost/X509TestCell/", cellRootUrl - + "#admin", target, roleList, schema); + + "#admin", target, roleList, schema, new String[] {"scope"}); String token = tcToken.toTokenString(); try { @@ -159,7 +159,7 @@ public static void beforeClass() { } TransCellAccessToken tcToken = new TransCellAccessToken("https://localhost/X509TestCell/", cellRootUrl - + "#admin", target, roleList, schema); + + "#admin", target, roleList, schema, new String[] {"scope"}); String token = tcToken.toTokenString(); @@ -194,7 +194,7 @@ public static void beforeClass() { } TransCellAccessToken tcToken = new TransCellAccessToken("https://localhost/X509TestCell/", cellRootUrl - + "#admin", target, roleList, schema); + + "#admin", target, roleList, schema, new String[] {"scope"}); String token = tcToken.toTokenString(); @@ -230,7 +230,7 @@ public static void beforeClass() { } TransCellAccessToken tcToken = new TransCellAccessToken("https://hoo/X509TestCell/", cellRootUrl + "#admin", - target, roleList, schema); + target, roleList, schema, new String[] {"scope"}); String token = tcToken.toTokenString(); @@ -269,7 +269,7 @@ public static void beforeClass() { } TransCellAccessToken tcToken = new TransCellAccessToken("https://localhost/X509TestCell/", cellRootUrl - + "#admin", target, roleList, schema); + + "#admin", target, roleList, schema, new String[] {"scope"}); String tokenStr = tcToken.toTokenString(); @@ -306,7 +306,7 @@ public static void beforeClass() { } TransCellAccessToken tcToken = new TransCellAccessToken("https://pio/X509TestCell/", cellRootUrl + "#admin", - target, roleList, schema); + target, roleList, schema, new String[] {"scope"}); String tokenStr = tcToken.toTokenString(); @@ -318,7 +318,7 @@ public static void beforeClass() { assertEquals(new CertificateException().getClass(), e.getCause().getClass()); // ログに出力されるメッセージの確認(真因メッセージはキャッチ出来る例外の1階層目に含まれている事) // CA証明書重複の場合、重複チェックでエラーになる - assertEquals("ca subject name already use.", e.getMessage()); + assertEquals("Duplicated ca subject names.", e.getMessage()); } catch (Exception e) { fail(e.getMessage()); } @@ -343,7 +343,7 @@ public static void beforeClass() { } TransCellAccessToken tcToken = new TransCellAccessToken("https://localhost/X509TestCell/", cellRootUrl - + "#admin", target, roleList, schema); + + "#admin", target, roleList, schema, new String[] {"scope"}); String token = tcToken.toTokenString(); try { @@ -378,7 +378,7 @@ public static void beforeClass() { // トークンのissuerにサーバ証明書のCN(localhost)と異なる値を設定する TransCellAccessToken tcToken = new TransCellAccessToken("https://hogehuga/X509TestCell/", cellRootUrl - + "#admin", target, roleList, schema); + + "#admin", target, roleList, schema, new String[] {"scope"}); String token = tcToken.toTokenString(); try { @@ -388,7 +388,6 @@ public static void beforeClass() { assertEquals(new KeySelectorException().getClass(), e.getCause().getClass()); // ログに出力されるメッセージの確認(真因メッセージはキャッチ出来る例外の1階層目に含まれている事) // CA証明書重複の場合、重複チェックでエラーになる - assertEquals("issure not equals.", e.getMessage()); } catch (Exception e) { fail(e.getMessage()); }