Path: blob/master/src/java.smartcardio/share/classes/javax/smartcardio/CardPermission.java
41153 views
/*1* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.smartcardio;2627import java.io.*;28import java.util.StringJoiner;29import java.security.Permission;3031/**32* A permission for Smart Card operations. A CardPermission consists of the33* name of the card terminal the permission applies to and a set of actions34* that are valid for that terminal.35*36* <p>A CardPermission with a name of <code>*</code> applies to all37* card terminals. The actions string is a comma separated list of the actions38* listed below, or <code>*</code> to signify "all actions."39*40* <p>Individual actions are:41* <dl>42* <dt>connect43* <dd>connect to a card using44* {@linkplain CardTerminal#connect CardTerminal.connect()}45*46* <dt>reset47* <dd>reset the card using {@linkplain Card#disconnect Card.disconnect(true)}48*49* <dt>exclusive50* <dd>establish exclusive access to a card using51* {@linkplain Card#beginExclusive} and {@linkplain Card#endExclusive52* endExclusive()}53*54* <dt>transmitControl55* <dd>transmit a control command using56* {@linkplain Card#transmitControlCommand Card.transmitControlCommand()}57*58* <dt>getBasicChannel59* <dd>obtain the basic logical channel using60* {@linkplain Card#getBasicChannel}61*62* <dt>openLogicalChannel63* <dd>open a new logical channel using64* {@linkplain Card#openLogicalChannel}65*66* </dl>67*68* @since 1.669* @author Andreas Sterbenz70* @author JSR 268 Expert Group71*/72public class CardPermission extends Permission {7374private static final long serialVersionUID = 7146787880530705613L;7576private final static int A_CONNECT = 0x01;77private final static int A_EXCLUSIVE = 0x02;78private final static int A_GET_BASIC_CHANNEL = 0x04;79private final static int A_OPEN_LOGICAL_CHANNEL = 0x08;80private final static int A_RESET = 0x10;81private final static int A_TRANSMIT_CONTROL = 0x20;8283// sum of all the actions above84private final static int A_ALL = 0x3f;8586private final static int[] ARRAY_MASKS = {87A_ALL,88A_CONNECT,89A_EXCLUSIVE,90A_GET_BASIC_CHANNEL,91A_OPEN_LOGICAL_CHANNEL,92A_RESET,93A_TRANSMIT_CONTROL,94};9596private final static String S_CONNECT = "connect";97private final static String S_EXCLUSIVE = "exclusive";98private final static String S_GET_BASIC_CHANNEL = "getBasicChannel";99private final static String S_OPEN_LOGICAL_CHANNEL = "openLogicalChannel";100private final static String S_RESET = "reset";101private final static String S_TRANSMIT_CONTROL = "transmitControl";102103private final static String S_ALL = "*";104105private final static String[] ARRAY_STRINGS = {106S_ALL,107S_CONNECT,108S_EXCLUSIVE,109S_GET_BASIC_CHANNEL,110S_OPEN_LOGICAL_CHANNEL,111S_RESET,112S_TRANSMIT_CONTROL,113};114115private transient int mask;116117/**118* @serial119*/120private final String actions;121122/**123* Constructs a new CardPermission with the specified actions.124* <code>terminalName</code> is the name of a CardTerminal or <code>*</code>125* if this permission applies to all terminals. <code>actions</code>126* contains a comma-separated list of the individual actions127* or <code>*</code> to signify all actions. For more information,128* see the documentation at the top of this {@linkplain CardPermission129* class}.130*131* @param terminalName the name of the card terminal, or <code>*</code>132* @param actions the action string (or null if the set of permitted133* actions is empty)134*135* @throws NullPointerException if terminalName is null136* @throws IllegalArgumentException if actions is an invalid actions137* specification138*/139public CardPermission(String terminalName, String actions) {140super(terminalName);141if (terminalName == null) {142throw new NullPointerException();143}144mask = getMask(actions);145this.actions = getActions(mask);146}147148private static int getMask(String actions) {149if (actions == null) {150return 0;151}152if (actions.length() == 0) {153throw new IllegalArgumentException("actions must not be empty");154}155156// try exact matches for simple actions first157for (int i = 0; i < ARRAY_STRINGS.length; i++) {158if (actions == ARRAY_STRINGS[i]) {159return ARRAY_MASKS[i];160}161}162163if (actions.endsWith(",")) {164throw new IllegalArgumentException("Invalid actions: '" + actions + "'");165}166int mask = 0;167String[] split = actions.split(",");168outer:169for (String s : split) {170for (int i = 0; i < ARRAY_STRINGS.length; i++) {171if (ARRAY_STRINGS[i].equalsIgnoreCase(s)) {172mask |= ARRAY_MASKS[i];173continue outer;174}175}176throw new IllegalArgumentException("Invalid action: '" + s + "'");177}178179return mask;180}181182private static String getActions(int mask) {183if (mask == 0) {184return null;185}186if (mask == A_ALL) {187return S_ALL;188}189StringJoiner sj = new StringJoiner(",");190for (int i = 0; i < ARRAY_MASKS.length; i++) {191final int action = ARRAY_MASKS[i];192if ((mask & action) == action) {193sj.add(ARRAY_STRINGS[i]);194}195}196return sj.toString();197}198199200/**201* Returns the canonical string representation of the actions.202* It is <code>*</code> to signify all actions defined by this class or203* the string concatenation of the comma-separated,204* lexicographically sorted list of individual actions.205*206* @return the canonical string representation of the actions.207*/208public String getActions() {209return actions;210}211212/**213* Checks if this CardPermission object implies the specified permission.214* That is the case, if and only if215* <ul>216* <li><p><code>permission</code> is an instance of CardPermission,</p>217* <li><p><code>permission</code>'s actions are a proper subset of this218* object's actions, and</p>219* <li><p>this object's <code>getName()</code> method is either220* <code>*</code> or equal to <code>permission</code>'s <code>name</code>.221* </p>222* </ul>223*224* @param permission the permission to check against225* @return true if and only if this CardPermission object implies the226* specified permission.227*/228public boolean implies(Permission permission) {229if (permission instanceof CardPermission == false) {230return false;231}232CardPermission other = (CardPermission)permission;233if ((this.mask & other.mask) != other.mask) {234return false;235}236String thisName = getName();237if (thisName.equals("*")) {238return true;239}240if (thisName.equals(other.getName())) {241return true;242}243return false;244}245246/**247* Compares the specified object with this CardPermission for equality.248* This CardPermission is equal to another Object <code>object</code>, if249* and only if250* <ul>251* <li><p><code>object</code> is an instance of CardPermission,</p>252* <li><p><code>this.getName()</code> is equal to253* <code>((CardPermission)object).getName()</code>, and</p>254* <li><p><code>this.getActions()</code> is equal to255* <code>((CardPermission)object).getActions()</code>.</p>256* </ul>257*258* @param obj the object to be compared for equality with this CardPermission259* @return true if and only if the specified object is equal to this260* CardPermission261*/262public boolean equals(Object obj) {263if (this == obj) {264return true;265}266if (obj instanceof CardPermission == false) {267return false;268}269CardPermission other = (CardPermission)obj;270return this.getName().equals(other.getName()) && (this.mask == other.mask);271}272273/**274* Returns the hash code value for this CardPermission object.275*276* @return the hash code value for this CardPermission object.277*/278public int hashCode() {279return getName().hashCode() + 31 * mask;280}281282private void writeObject(ObjectOutputStream s) throws IOException {283// Write out the actions. The superclass takes care of the name.284s.defaultWriteObject();285}286287private void readObject(ObjectInputStream s)288throws IOException, ClassNotFoundException {289// Read in the actions, then restore the mask.290s.defaultReadObject();291mask = getMask(actions);292}293}294295296