/* * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javax.smartcardio; import java.io.*; import java.security.Permission; /** * A permission for Smart Card operations. A CardPermission consists of the * name of the card terminal the permission applies to and a set of actions * that are valid for that terminal. * *

A CardPermission with a name of * applies to all * card terminals. The actions string is a comma separated list of the actions * listed below, or * to signify "all actions." * *

Individual actions are: *

*
connect *
connect to a card using * {@linkplain CardTerminal#connect CardTerminal.connect()} * *
reset *
reset the card using {@linkplain Card#disconnect Card.disconnect(true)} * *
exclusive *
establish exclusive access to a card using * {@linkplain Card#beginExclusive} and {@linkplain Card#endExclusive * endExclusive()} * *
transmitControl *
transmit a control command using * {@linkplain Card#transmitControlCommand Card.transmitControlCommand()} * *
getBasicChannel *
obtain the basic logical channel using * {@linkplain Card#getBasicChannel} * *
openLogicalChannel *
open a new logical channel using * {@linkplain Card#openLogicalChannel} * *
* * @since 1.6 * @author Andreas Sterbenz * @author JSR 268 Expert Group */ public class CardPermission extends Permission { private static final long serialVersionUID = 7146787880530705613L; private final static int A_CONNECT = 0x01; private final static int A_EXCLUSIVE = 0x02; private final static int A_GET_BASIC_CHANNEL = 0x04; private final static int A_OPEN_LOGICAL_CHANNEL = 0x08; private final static int A_RESET = 0x10; private final static int A_TRANSMIT_CONTROL = 0x20; // sum of all the actions above private final static int A_ALL = 0x3f; private final static int[] ARRAY_MASKS = { A_ALL, A_CONNECT, A_EXCLUSIVE, A_GET_BASIC_CHANNEL, A_OPEN_LOGICAL_CHANNEL, A_RESET, A_TRANSMIT_CONTROL, }; private final static String S_CONNECT = "connect"; private final static String S_EXCLUSIVE = "exclusive"; private final static String S_GET_BASIC_CHANNEL = "getBasicChannel"; private final static String S_OPEN_LOGICAL_CHANNEL = "openLogicalChannel"; private final static String S_RESET = "reset"; private final static String S_TRANSMIT_CONTROL = "transmitControl"; private final static String S_ALL = "*"; private final static String[] ARRAY_STRINGS = { S_ALL, S_CONNECT, S_EXCLUSIVE, S_GET_BASIC_CHANNEL, S_OPEN_LOGICAL_CHANNEL, S_RESET, S_TRANSMIT_CONTROL, }; private transient int mask; /** * @serial */ private volatile String actions; /** * Constructs a new CardPermission with the specified actions. * terminalName is the name of a CardTerminal or * * if this permission applies to all terminals. actions * contains a comma-separated list of the individual actions * or * to signify all actions. For more information, * see the documentation at the top of this {@linkplain CardPermission * class}. * * @param terminalName the name of the card terminal, or * * @param actions the action string (or null if the set of permitted * actions is empty) * * @throws NullPointerException if terminalName is null * @throws IllegalArgumentException if actions is an invalid actions * specification */ public CardPermission(String terminalName, String actions) { super(terminalName); if (terminalName == null) { throw new NullPointerException(); } mask = getMask(actions); } private static int getMask(String actions) { if ((actions == null) || (actions.length() == 0)) { throw new IllegalArgumentException("actions must not be empty"); } // try exact matches for simple actions first for (int i = 0; i < ARRAY_STRINGS.length; i++) { if (actions == ARRAY_STRINGS[i]) { return ARRAY_MASKS[i]; } } if (actions.endsWith(",")) { throw new IllegalArgumentException("Invalid actions: '" + actions + "'"); } int mask = 0; String[] split = actions.split(","); outer: for (String s : split) { for (int i = 0; i < ARRAY_STRINGS.length; i++) { if (ARRAY_STRINGS[i].equalsIgnoreCase(s)) { mask |= ARRAY_MASKS[i]; continue outer; } } throw new IllegalArgumentException("Invalid action: '" + s + "'"); } return mask; } private static String getActions(int mask) { if (mask == A_ALL) { return S_ALL; } boolean first = true; StringBuilder sb = new StringBuilder(); for (int i = 0; i < ARRAY_MASKS.length; i++) { int action = ARRAY_MASKS[i]; if ((mask & action) == action) { if (first == false) { sb.append(","); } else { first = false; } sb.append(ARRAY_STRINGS[i]); } } return sb.toString(); } /** * Returns the canonical string representation of the actions. * It is * to signify all actions defined by this class or * the string concatenation of the comma-separated, * lexicographically sorted list of individual actions. * * @return the canonical string representation of the actions. */ public String getActions() { if (actions == null) { actions = getActions(mask); } return actions; } /** * Checks if this CardPermission object implies the specified permission. * That is the case, if and only if * * * @param permission the permission to check against * @return true if and only if this CardPermission object implies the * specified permission. */ public boolean implies(Permission permission) { if (permission instanceof CardPermission == false) { return false; } CardPermission other = (CardPermission)permission; if ((this.mask & other.mask) != other.mask) { return false; } String thisName = getName(); if (thisName.equals("*")) { return true; } if (thisName.equals(other.getName())) { return true; } return false; } /** * Compares the specified object with this CardPermission for equality. * This CardPermission is equal to another Object object, if * and only if * * * @param obj the object to be compared for equality with this CardPermission * @return true if and only if the specified object is equal to this * CardPermission */ public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof CardPermission == false) { return false; } CardPermission other = (CardPermission)obj; return this.getName().equals(other.getName()) && (this.mask == other.mask); } /** * Returns the hash code value for this CardPermission object. * * @return the hash code value for this CardPermission object. */ public int hashCode() { return getName().hashCode() + 31 * mask; } private void writeObject(ObjectOutputStream s) throws IOException { // Write out the actions. The superclass takes care of the name. // Call getActions to make sure actions field is initialized if (actions == null) { getActions(); } s.defaultWriteObject(); } private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { // Read in the actions, then restore the mask. s.defaultReadObject(); mask = getMask(actions); } }