package net.deterlab.abac; import java.util.*; import org.bouncycastle.asn1.*; /** * Represents a role, which is a vertex in a Credential graph. */ public class Role implements Comparable { private String m_string; private String[] m_parts; private String m_A_r1, m_r2; private String m_prefix; private Role[] m_prereqs; protected static TreeMap nicknames = new TreeMap(); protected static TreeMap keys = new TreeMap(); /** * Create a role from a string. A single role must be of the format "A", * "A.r1", or "A.r1.r2", where A is a principal and r1 and r2 are role * names. This constructor also supports intersection roles: a sequence of * two or more roles separated by "&". The whitespace surrounding & * is arbitrary. * * If the string does not have this format, the constructor throws a * RuntimeException. */ public Role(String s) throws RuntimeException { m_string = s; // intersection roles have at least two roles separated by "&" String[] isect_roles = s.split("&"); // ordinary role if (isect_roles.length == 1) single_role(); // intersection role: make a list of prereqs else { m_prereqs = new Role[isect_roles.length]; for (int i = 0; i < isect_roles.length; ++i) m_prereqs[i] = new Role(isect_roles[i].trim()); // trim() handles arbitrary whitespace // this make is_principal etc. work properly m_parts = new String[0]; } } public Role(String s, boolean translate) { this(translate ? replace(s, nicknames) : s); } /** * Initialize a single non-intersection role. See constructor for details of * role format. Will throw RuntimeException if the role is invalid. */ private void single_role() throws RuntimeException { m_parts = m_string.split("\\."); if (m_parts.length > 3) throw new RuntimeException("Not a valid role: " + m_string); // linking role: prefix is A.r1 from A.r1.r2 if (is_linking()) { m_A_r1 = m_parts[0] + "." + m_parts[1]; m_r2 = m_parts[2]; m_prefix = m_A_r1; } // role: prefix is A from A.r1 else if (is_role()) m_prefix = m_parts[0]; // principal: prefix is the whole thing else m_prefix = m_string; } /** * Returns true iff the role is a principal. */ public boolean is_principal() { return m_parts.length == 1; } /** * Returns true iff the role is a role (i.e., A.r1). */ public boolean is_role() { return m_parts.length == 2; } /** * Returns true iff the role is a linking role (i.e., A.r1.r2). */ public boolean is_linking() { return m_parts.length == 3; } /** * Returns true iff the role represents an intersection role. */ public boolean is_intersection() { return m_prereqs != null; } /** * Returns the first two elements of a linking role's name. This typically * refers to another role in the graph. This will throw a runtime * exception if the node is not a linking role. */ public String A_r1() throws RuntimeException { if (!is_linking()) throw new RuntimeException("Not a linking role"); return m_A_r1; } /** * Return the last element of a linking role's name. This will throw a * runtime exception if the node is not a linking role. */ public String r2() throws RuntimeException { if (!is_linking()) throw new RuntimeException("Not a linking role"); return m_r2; } /** * Returns the principal part of a role or principal. This is everything * except the last element of the name. */ public String principal_part() { return m_prefix; } /** * Returns an issuer, only the first element. */ public String issuer_part() { return m_parts[0]; } /** * Returns true if the principal part of the name matches a prefix. This * is used when filtering graphs. */ public boolean matches(String prefix) { return prefix.length() == 0 || m_prefix.equals(prefix); } /** * Get the roles that form the prerequisites to this intersection. Throws * a runtime exception if this is not an intersection role. */ public Role[] prereqs() throws RuntimeException { if (!is_intersection()) throw new RuntimeException("Not an intersection role."); return m_prereqs; } public String toString() { return m_string; } public String simpleString() { return replace(m_string, keys); } public boolean equals(Object v2) { if (v2 instanceof Role) return m_string.equals(((Role)v2).m_string); return false; } public int compareTo(Object o) { if (o instanceof Role) return m_string.compareTo(((Role)o).m_string); else return 1; } public int hashCode() { return m_string.hashCode(); } /** * Translate either keys to nicknames or vice versa. Break the string into * space separated tokens and then each of them into period separated * strings. If any of the smallest strings is in the map, replace it with * the value. */ protected static String replace(String is, Map m) { String rv = ""; for (String tok: is.split(" ")) { String term = ""; for (String s: tok.split("\\.")) { String next = m.containsKey(s) ? m.get(s) : s; if (term.isEmpty()) term = next; else term += "." + next; } if (rv.isEmpty()) rv = term; else rv += " " + term; } return rv; } public static void add_mapping(String name, String key) { nicknames.put(name, key); keys.put(key,name); } public static boolean key_in_mapping(String key) { return keys.containsKey(key); } public static boolean name_in_mapping(String name) { return nicknames.containsKey(name); } public static void clear_mapping() { nicknames.clear(); keys.clear(); } }