/** * 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.model.jaxb; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.xml.bind.JAXBException; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElements; import javax.xml.bind.annotation.XmlRootElement; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; import com.fujitsu.dc.common.auth.token.Role; import com.fujitsu.dc.common.utils.DcCoreUtils; import com.fujitsu.dc.core.DcCoreException; import com.fujitsu.dc.core.auth.AccessContext; import com.fujitsu.dc.core.auth.BoxPrivilege; import com.fujitsu.dc.core.auth.CellPrivilege; import com.fujitsu.dc.core.auth.Privilege; /** * ACLを表すモデルオブジェクト. * WebDAV ACLの D:acl タグに対応したJAXBオブジェクトとしても振る舞い、 * ACLメソッドで受けるXMLをそのまま unmarshall してオブジェクト生成可能。 * 一方で、JSONへの シリアライズ及び JSONからのデシリアライズもサポートし、 * ElasticSearchをはじめとするJSONベースの永続化機構での利用を可能とする。 * また、AccessContextオブジェクトに本オブジェクトを与えることで、 * 与えられるべきPrivilege一覧を生成する。 */ @XmlAccessorType(XmlAccessType.FIELD) //@XmlType(name = "", propOrder = { "aces" }) @XmlRootElement(namespace = "DAV:", name = "acl") public final class Acl { /** * xml:base. */ @XmlAttribute(namespace = "http://www.w3.org/XML/1998/namespace") String base; /** * dc:requireSchemaAuthz. */ @XmlAttribute(namespace = DcCoreUtils.XmlConst.NS_DC1) String requireSchemaAuthz; /** * dc:requireSchemaAuthz setter. * @param requireSchemaAuthz requireSchemaAuthz */ public void setRequireSchemaAuthz(String requireSchemaAuthz) { this.requireSchemaAuthz = requireSchemaAuthz; } /** * dc:requireSchemaAuthz getter. * @return requireSchemaAuthz */ public String getRequireSchemaAuthz() { return requireSchemaAuthz; } /** * Aceタグ. */ @XmlElements({ @XmlElement(namespace = "DAV:", name = "ace", type = Ace.class) }) List<Ace> aces; /** * xml:base setter. * @param base baseUrl */ public void setBase(String base) { this.base = base; } /** * xml:base getter. * @return base */ public String getBase() { return base; } /** * Ace. * @return Ace Object */ public List<Ace> getAceList() { return aces; } /** * JSON化する. * @return Mapオブジェクト */ public String toJSON() { StringWriter sw = new StringWriter(); try { ObjectIo.toJson(this, sw); return sw.toString(); } catch (IOException e) { throw DcCoreException.Server.DATA_STORE_UNKNOWN_ERROR.reason(e); } catch (JAXBException e) { throw DcCoreException.Server.DATA_STORE_UNKNOWN_ERROR.reason(e); } } static final String KEY_REQUIRE_SCHEMA_AUTHZ = "@requireSchemaAuthz"; /** * @param jsonString acl json * @return Acl obj */ public static Acl fromJson(final String jsonString) { StringReader sr = new StringReader(jsonString); try { Acl ret = ObjectIo.fromJson(sr, Acl.class); // attr somehow not unmarshalled so manually fix the object JSONParser parser = new JSONParser(); JSONObject j = (JSONObject) parser.parse(jsonString); ret.setRequireSchemaAuthz((String) j.get(KEY_REQUIRE_SCHEMA_AUTHZ)); return ret; } catch (IOException e) { throw DcCoreException.Server.DATA_STORE_UNKNOWN_ERROR.reason(e); } catch (JAXBException e) { throw DcCoreException.Server.DATA_STORE_UNKNOWN_ERROR.reason(e); } catch (ParseException e) { throw DcCoreException.Server.DATA_STORE_UNKNOWN_ERROR.reason(e); } } /** * AccessContextに対して、このACLがどのようなPrivilegeを与えるかを返す. * @param ac AccessContextオブジェクト * @return Privilege List */ public List<String> allows(final AccessContext ac) { List<Role> roles = ac.getRoleList(); List<String> ret = new ArrayList<String>(); for (Role role : roles) { for (Ace ace : this.aces) { if (ace.getPrincipalHref().equals(role.createUrl())) { List<String> privList = ace.getGrantedPrivilegeList(); for (String priv : privList) { ret.add(priv); } } } } return ret; } /** * AccessContextに対して、このACLが特定のPrivilegeを与えるかどうかを返す. * @param priv チェックしたいPrivilege * @param ac AccessContextオブジェクト * @param privilegeMap Privilege管理 * @return 与える場合は真 */ public boolean allows(final Privilege priv, final AccessContext ac, Map<String, Privilege> privilegeMap) { List<String> privs = this.allows(ac); boolean ret = false; for (String p : privs) { Privilege pObj = privilegeMap.get(p); if (pObj.includes(priv)) { ret = true; } } return ret; } /** * ACLのバリデートチェック処理. * @param isCellLevel Cellレベルかのフラグ * @return バリデートに異常がある場合はfalseを返却 */ public boolean validateAcl(boolean isCellLevel) { // <!ELEMENT acl (ace*) > if (aces == null) { return true; } for (Ace ace : aces) { // <!ELEMENT ace ((principal or invert), (grant or deny), protected?,inherited?)> if (ace.grant == null || ace.principal == null) { return false; } // <!ELEMENT grant (privilege+)> if (ace.grant.privileges == null) { return false; } Map<String, CellPrivilege> cellPrivilegeMap = CellPrivilege.getPrivilegeMap(); Map<String, BoxPrivilege> boxPrivilegeMap = BoxPrivilege.getPrivilegeMap(); for (com.fujitsu.dc.core.model.jaxb.Privilege privilege : ace.grant.privileges) { // privilegeが空でないこと if (privilege.body == null) { return false; } // Privilegeに設定可能なタグであるかチェック if (isCellLevel) { if (!cellPrivilegeMap.containsKey(privilege.body.getLocalName())) { return false; } } else { if (!boxPrivilegeMap.containsKey(privilege.body.getLocalName())) { return false; } } } // <!ELEMENT principal (href or all)> // <!ELEMENT href ANY> if (ace.principal.all == null && (ace.principal.href == null || ace.principal.href.equals(""))) { return false; } } return true; } }