All Packages This Package Class Hierarchy Class Search Index
java.lang.Object | +----glguerin.authkit.Authorization
Summary |
public abstract class Authorization extends java.lang.Object { // Fields 13 public static final int HAS_PROCESS_COUPLED_STREAMS; public static final int HAS_PROCESS_DESTROY; public static final int HAS_PROCESS_ELEVATED; public static final int HAS_PROCESS_ERRORSTREAM; public static final int HAS_PROCESS_EXITVALUE; public static final int HAS_PROCESS_INPUTSTREAM; public static final int HAS_PROCESS_OUTPUTSTREAM; public static final int HAS_PROCESS_WAITFOR; public static final int HAS_SESSION_MULTIPROCESS; public static final int HAS_SYNTHETIC_PREAUTH; public static final int WHEN_EARLIEST; public static final int WHEN_LATEST; protected Hashtable pastGranted; // Constructors 1 protected Authorization(); // Methods 23 protected void addGranted(Privilege); public abstract void attach(byte[]); public abstract void attachPrivileged(); public abstract void authorize(Privilege, boolean); protected void clearGranted(); public abstract void detach(boolean); public abstract Process execPrivileged(String[]); protected void finalize() throws Throwable; protected String formFingerprint(String, byte[]); public abstract int getCapabilities(); public abstract Date getPastGrantedDate(Privilege, int); public abstract Enumeration getPastGrantedPrivileges(); public String getPublicIdentifier(); public abstract byte[] getSecretIdentifier(); public abstract int getSecretLength(); public abstract boolean isAvailable(Privilege); public boolean isCapable(int); protected Enumeration keysGranted(); public abstract Privilege makeExecPrivilege(String); public byte[] makeFingerprint(String); public abstract void preauthorize(Privilege); public void release(); protected Date whenGranted(Privilege, int); }
An Authorization is a high-level way to manage access to restricted parts of a Java program, or to privileged functionality provided by the system, such as executing another program with elevated privileges (i.e. with and effective user-ID of root). Instances of the Privilege class represent named individual privileges or groups of privileges. Access to restricted services is granted or denied with one principal method: authorize(). Privileged execution of other programs is controlled by one method: execPrivileged(). Other methods supplement these core facilities. An Authorization is essentially a simple facade placed over any kind of implementation one cares to use or provide.
The Authorization class is abstract, so a concrete implementation is always needed. Different concrete implementations can perform authentication and authorization in different ways, using different mechanisms or credentials. A concrete implementation may be platform-neutral or platform-specific. It can be based on any underlying technology desired. For example, it's possible to implement Authorization using smart-cards, USB biometric devices, JAAS, Kerberos, or almost any other authentication and authorization technology.
An Authorization isn't really like any of the existing Java classes or frameworks that provide access controls, because it takes a very high-level view and hides all the details within its implementation. All the details of principals, subjects, identities, roles, credentials, policies, authenticators, pre-conditions, expiries, etc. are hidden in the specific implementation. That implementation may be entirely self-enforced (say, by java.security classes), or it may be entirely system-enforced (say, by Mac OS X's Auth Services or by Kerberos), or it may be some balance between self-enforced and system-enforced facilities.
A concrete Authorization is provided for Mac OS X, based on the Authorization Services API. As a result, it can execute other programs, including Java programs, with an effective user-ID of root. This execution is controlled through a system-enforced authentication dialog, under system-provided and system-restricted authorization policies. That is, the transition to an effective user-ID of root is entirely system-controlled.
Any Java program executing a process with elevated privileges must be entirely trustworthy itself, and it must remain trustworthy. If the Java program or any of its components can be altered by an unprivileged agent, then the program can be "turned to the Dark Side" for possible malicious ends. This is always true for any program using any kind of Authorization -- if you can't trust it's entire chain of provenance, you shouldn't trust that it will act properly with elevated privileges.
In any Authorization implementation, some Privileges may only be effectively exercised by executing another program (process). The threshold at which this becomes necessary is implementation-dependent. On typical Unix-like systems, a process is the smallest entity that can have distinct enforceable privileges, rather than a thread, a class, or an object. Mac OS X works this way, so if special system-enforced privileges are needed, it may require a separate process to do it. That's why execPrivileged() exists.
The threshold of when to execute another process may be affected by the use of setuid and setgid processes, or by the manipulation of effective uid and gid within a single process. Nothing in standard Java knows anything about setuid or setgid processes. Neither does any implementation of Authorization. You may be able to use my Easy Posix Toolkit for Java to manage a process's real and effective uid/gid's.
A newly instantiated Authorization is not attached to any session. A session may be explicitly attached with either of two methods, or implicitly by calling certain Authorization methods. Once attached to a session, an Authorization remains attached to the same session until explicitly detached, or until the current process terminates. Process termination is equivalent to release() or detach(false).
One way to attach an Authorization to an existing session is possible if you know the session's secret identifier. You can also attach to an existing session if you have privileged access, but only when the current process is a child by execPrivileged().
If no session is attached, the following Authorization methods will implicitly create and attach a new session:
To ensure that a session is attached, the simplest approach is to call isAvailable() with a dummy Privilege, such as Privilege.EMPTY. Since isAvailable() will create a session as needed, yet won't throw an UnauthorizedException, you can call it for the side-effect of creating a session as needed. Just ignore whether the dummy Privilege is available or not.
The following methods never cause automatic session creation:
"Self-enforced" or "self-restricted" means that either your own code or some code in the Java environment enforces access controls. For example, Java's extensive security infrastructure is entirely self-enforced, largely by classes written by Sun or other security-library providers. Those classes call SecurityManager or AccessController methods at appropriate points in their execution, so that desired security policies are enforced in the intended way. If calls weren't done at the proper points, then the policies would not be enforced.
"System-enforced" or "self-restricted" means that the OS itself, or at least some entity outside the Java environment, enforces access controls. An example of a system-enforced privilege might be access to a file owned by some other user-account. Even if Java's security policies (or JAAS's policies) state that your program has full access to the file-system, you still can't access files or directories that the system forbids you from accessing. For example, many system files and directories are not public-writable on Mac OS X. If your Java app tries to write them, the attempt fails, even when there is no stated Java security policy preventing it. It fails because the system is enforcing a policy, not because Java is enforcing one. As another example, must user-accounts on Mac OS X do not have public-read permission on most of the home-directory's contents. If you aren't logged in as that user, you can't read their files or see into their directories, even if you have unrestricted Java privileges.
A system-enforced privilege must use system-provided access mechanisms in order to succeed. Such mechanisms may be system-dependent or unsupported in plain Java. Some mechanisms are supported in plain Java, such as a few in java.io.File. Many more mechanisms are not supported or even known in plain Java.
The whole purpose of the Authorization class is to give Java access to a system-provided mechanism, when it exists. Since this is a fairly simple class, it provides some hope of being ported to other systems, or of being adapted to other mechanisms.
The amount and kind of system-enforcement depends on the system. Different OSes enforce different rules under different circumstances, and different user-IDs have different privileges on a given OS (e.g. root vs. admin user vs. ordinary user on Mac OS X). Also, different things may be restricted by different mechanisms. For example, some things are restricted by user-ID, while others are restricted by group-ID. Or a given platform may have Access-Control Lists (ACL's), or there may be other mechanisms used (smart-cards, dongles, biometrics, whatever).
The Authorization class does not require any particular access-control policy or mechanism. Nor does it require any particular division of self-enforced vs. system-enforced privilege. You could create an implementation using AWT or Swing Dialogs, if you wanted. If the goal was to truly grant root-user privileges, though, you'd still have to figure out some way of doing that securely for your target platform.
See Also: Privilege
Cross Reference |
Fields |
· HAS_PROCESS_COUPLED_STREAMS | Summary | Top |
public static final int HAS_PROCESS_COUPLED_STREAMS
The bit-mask for getCapabilities() or isCapable() signifying that the Process returned by execPrivileged() has interdependent streams returned from getInputStream() and getOutputStream(), so that closing one also closes the other. Without this capability, which is really a shortcoming, the returned Process's streams are completely independent.
When a Process has this shortcoming, it affects what kind of programs can be run by execPrivileged() and how information can be sent back and forth between the processes.
· HAS_PROCESS_INPUTSTREAM | Summary | Top |
public static final int HAS_PROCESS_INPUTSTREAM
The bit-mask for getCapabilities() or isCapable() signifying that the Process returned by execPrivileged() will return an InputStream from getInputStream(). Without this capability, the Process will throw an IllegalArgumentException when getInputStream() is called.
· HAS_PROCESS_OUTPUTSTREAM | Summary | Top |
public static final int HAS_PROCESS_OUTPUTSTREAM
The bit-mask for getCapabilities() or isCapable() signifying that the Process returned by execPrivileged() will return an InputStream from getOutputStream(). Without this capability, the Process will throw an IllegalArgumentException when getOutputStream() is called.
· HAS_PROCESS_ERRORSTREAM | Summary | Top |
public static final int HAS_PROCESS_ERRORSTREAM
The bit-mask for getCapabilities() or isCapable() signifying that the Process returned by execPrivileged() will return an InputStream from getErrorStream(). Without this capability, the Process will throw an IllegalArgumentException when getErrorStream() is called.
· HAS_PROCESS_EXITVALUE | Summary | Top |
public static final int HAS_PROCESS_EXITVALUE
The bit-mask for getCapabilities() or isCapable() signifying that the Process returned by execPrivileged() implements exitValue(). Without this capability, the Process will throw an IllegalArgumentException when exitValue() is called.
· HAS_PROCESS_WAITFOR | Summary | Top |
public static final int HAS_PROCESS_WAITFOR
The bit-mask for getCapabilities() or isCapable() signifying that the Process returned by execPrivileged() implements waitFor(). Without this capability, the Process will throw an IllegalArgumentException when waitFor() is called.
· HAS_PROCESS_DESTROY | Summary | Top |
public static final int HAS_PROCESS_DESTROY
The bit-mask for getCapabilities() or isCapable() signifying that the Process returned by execPrivileged() implements destroy(). Without this capability, the Process will throw an IllegalArgumentException when destroy() is called.
· HAS_PROCESS_ELEVATED | Summary | Top |
public static final int HAS_PROCESS_ELEVATED
The bit-mask for getCapabilities() or isCapable() signifying that the Process returned by execPrivileged() will really be running with elevated privileges of some kind. Without this capability, the child Process does not have elevated or special privileges. In effect, this bit-mask tells whether execPrivileged() is real or not.
· HAS_SYNTHETIC_PREAUTH | Summary | Top |
public static final int HAS_SYNTHETIC_PREAUTH
The bit-mask for getCapabilities() or isCapable() signifying that preauthorize(priv) is synthesized simply by calling authorize(priv,true). Without this capability, which is really a shortcoming, the Authorization implements preauthorize() and authorize() as completely distinct operations.
See Also: preauthorize
· HAS_SESSION_MULTIPROCESS | Summary | Top |
public static final int HAS_SESSION_MULTIPROCESS
The bit-mask for getCapabilities() or isCapable() signifying that a session may be attached to by multiple processes, and that a session's secret identifier will work across process boundaries. Without this capability, secret identifiers do not work across multiple processes.
See Also: getPublicIdentifier, getSecretIdentifier, attach
· WHEN_EARLIEST | Summary | Top |
public static final int WHEN_EARLIEST
Values for the 'when' arg passed to getPastGrantedDate().
See Also: getPastGrantedDate
· WHEN_LATEST | Summary | Top |
public static final int WHEN_LATEST
Values for the 'when' arg passed to getPastGrantedDate().
See Also: getPastGrantedDate
· pastGranted | Summary | Top |
protected Hashtable pastGranted
Holds past Privileges granted -- key: Privilege, value: long[2]. The long[] holds timestamps as milliseconds-since-epoch, indexed by 'when'.
Although visible to the protected scope, there are protected methods which provide most of the useful functionality for concrete implementations. Use the protected methods first, and only access this field directly if there's no other way to accomplish the intended goal.
Constructors |
· Authorization | Summary | Top |
protected Authorization()
May only be subclassed.
Methods |
· finalize | Summary | Top |
protected void finalize() throws Throwable
The default finalizer for any instance of Authorization calls its detach(false) method, so an unreferenced underlying session does not malinger.
This implementation catchs all Throwables and ignores them here. Doing this here ensures that a gc'ed Authorization will not cause the finalizer Thread to hiccup.
Do not override this method unless you are fully aware of the consequences.
- Overrides:
- finalize in class Object
· getCapabilities | Summary | Top |
public abstract int getCapabilities()
Return a set of bits in an int, signifying capabilities or characteristics. More than one bit may be set, or no bits may be set.
Some capabilities are actually shortcomings or limitations that an Authorization's caller may need or want to distinguish.
Identify the individual capabilities using the bit-masks defined by the HAS_XXX named constants of this class.
This method never throws an exception, nor does it need a session active.
See Also: isCapable
· isCapable | Summary | Top |
public boolean isCapable(int bitMask)
Return T if and only if all the capabilities represented by 1-bits in bitMask are present in this Authorization's getCapabilities() value. If bitMask has a single set bit, then the returned boolean signifies a single capability. If bitMask has more than one set bit, then the returned boolean signifies the combined capabilities. In short, T is returned only when all the capabilities represented by the bitMask are available.
This is a convenience method that returns:
(getCapabilities() & bitMask) == bitMask
See Also: getCapabilities
· authorize | Summary | Top |
public abstract void authorize(Privilege toGrant, boolean interactionAllowed)
Authorize the given Privilege, granting approval to exercise it immediately. If the Privilege is granted or was already available, this method returns normally. If the Privilege is not granted, then the user is authenticated using whatever means or mechanisms the implementation deems appropriate. If the Privilege is not granted and can't be authenticated, an UnauthorizedException is thrown.
Interactive authentication with the user is allowed or disallowed according to 'interactionAllowed'. The current thread is blocked while any user-interaction is occurring. If interaction is allowed, and the user does not authenticate properly, this method fails. If interaction is disallowed, and the privilege is not already available, this method fails.
The interactionAllowed flag is not a demand for user interaction or authentication. It is simply a way to tell the underlying authentication arbiter whether a thread-blocking user interaction is permitted or not. If authentication is needed, but interaction is disallowed, then an exception is thrown. If authentication isn't needed, as determined by the implementation, then the state of 'interactionAllowed' is irrelevant, and no interaction occurs.
This method is the principal way to guard (protect) a privileged sequence of code. Place a call to this method, with an appropriate Privilege, before any restricted section of code. Throwing the UnauthorizedException prevents execution of the subsequent restricted code. You can allow or disallow user-interaction as appropriate to your application.
In general, if a restricted section of your code can't survive with the thread-blocking that may occur when interactionAllowed is true, you should call preauthorize() from a place in your code where interaction is allowable, then call authorize() with interaction disallowed immediately before the restricted code section.
You should typically place invocations of this method within a try/catch block, catching an UnauthorizedException or IllegalArgumentException and handling it appropriately. DO NOT IGNORE THESE EXCEPTIONS. Letting your program terminate with an uncaught exception is ungraceful at best. Permitting a restricted action is worse than ungraceful, it's a security failure. You may wish to catch UnauthorizedExceptions separately from other SecurityExceptions, or you may wish to catch them all under a single SecurityException catch clause.
This method also "lapses" the granted Privilege, if it has an expiration. For example, if a prior preauthorize() succeeded, then that preauthorization will undergo any expiration conditions established by the controlling policy. If the policy states that the privilege has a timeout=0, then authorize() will "lapse" or "consume" the pending preauthorization, so the next call to authorize() or preauthorize() will require user authentication again.
This "lapsing" only occurs if preauthorize() is really performing a preauthorization, as indicated by the absence of HAS_SYNTHETIC_PREAUTH in getCapabilities(). If preauthorize() doesn't really perform preauthorization, then policies or rules with timeout=0 will be problematic.
- Throws: UnauthorizedException
- thrown when the requested Privilege is not granted.
- Throws: IllegalArgumentException
- thrown when the Privilege is malformed, or some other structural error occurs.
· preauthorize | Summary | Top |
public abstract void preauthorize(Privilege toGrant)
Preauthorize the given Privilege, obtaining the ability to exercise it at a later point with authorize(). User interaction will always occur if the Privilege is not already available. You can't control interaction as you can with authorize(). If the Privilege is not granted, an UnauthorizedException is thrown.
If a Privilege is successfully preauthorized, then a subsequent authorize() will see that Privilege already available. The authorize() method will then not have to interact with the user, so authorize() will succeed even if interaction is disallowed.
Preauthorizing differs from authorizing in that preauthorizing obtains a privilege for subsequent use, rather than exercising the granted privilege immediately. The purpose of preauthorize() is to interactively authenticate when interaction is possible for the application, yet still call authorize() when the privilege must be available. It effectively separates the claiming of the privilege from the exercising of it.
This method may or may not implement true preauthorization. You can determine whether it does or not by the state of HAS_SYNTHETIC_PREAUTH in getCapabilities(). If the flag-bit is set, then preauthorize() is synthesized, effectively calling authorize() with interaction allowed.
A synthetic preauthorize() will have problems when policy rules have a timeout=0. The best way to understand why is to consider what happens when preauthorize() is real. When it's real, preauthorize() effectively "cocks the hammer" of a privilege, but doesn't "pull the trigger". The call to authorize() pulls the trigger. So if a rule with timeout=0 is preauthorized, the implementation knows the privilege has been authenticated, but the timeout has not been started yet. The timeout for any rule or policy only starts when authorize() is called. So preauthorizing a timeout=0 rule is effectively creating a single-use credential for that privilege, allowing it to be used (authorized) only once. After that one use, the timeout=0 value prevents any subsequent use until another authentication occurs.
Given that behavior for a real (non-synthetic) preauthorize(), we can now see the problem with a synthetic preauthorize(). It's the timeout. When preauthorize() is synthetic, it has the same effect as authorize(). But authorize() starts the timeout. So when timeout=0, a preauthorize() is ultimately ineffective, because authorize() will have to reauthenticate. If interaction is allowed in authorize(), the user sees something really annoying and really stupid: back-to-back authentication dialogs. This is even more stupid than usual, because security-conscious users may think the first dialog was a spoof, and start to suspect their machine has been compromised.
The moral of all this is to use a synthetic preauthorize() cautiously. Unfortunately, there's no way to inquire about timeouts for rules or policies. This is a consequence of the Authorization Services API, which has no facility for discovering rules, timeouts, remaining time till expiry, etc.
- Throws: UnauthorizedException
- thrown when the requested Privilege is not granted.
- Throws: IllegalArgumentException
- thrown when the Privilege is malformed, or some other structural error occurs.
· isAvailable | Summary | Top |
public abstract boolean isAvailable(Privilege toCheck)
Is the given Privilege currently available (authorized, preauthorized, or implied)?
This method determines whether the given Privilege is available, without actually exercising it, and without lapsing any existing preauthorization.
A Privilege that has been preauthorized will return true from this method, without triggering any expiration policies that may affect the privilege. Privileges already authorized (such as by a parent process) and available to the current process will also return true.
DO NOT use this method to perform an authentication or authorization check. Always and only use authorize() for doing authorization checks that guard restricted code. The isAvailable() method is mainly for when you want to examine a current authorization state, such as to determine the initial or ongoing visual status of a GUI control, or to decide whether to preauthorize() or not.
A privilege may be available without ever having been explicitly authorized or granted. For example, a root user already has the execute-as-root privilege needed by execPrivileged(). This is true even if the user has not been overtly authenticated or authorized by the program, and regardless of whether authorize() or preauthorize() is ever called.
If the given Privilege has not been granted, this method does nothing that will grant it. Also, if the Privilege was previously granted but is now expired, this method does nothing to refresh or reauthenticate the underlying credential or authorization.
Whether the Privilege is available or not, this method has no effect on the enumerated Privileges returned by getPastGrantedPrivileges(). That is, calling this method does not affect the list of past granted Privileges. Only authorize() or preauthorize() will add Privileges, and only detach() will remove them from the list.
This method won't throw an UnauthorizedException.
- Throws: IllegalArgumentException
- thrown when the Privilege is malformed, or some other structural error occurs.
· attach | Summary | Top |
public abstract void attach(byte[] secretIdentifier)
Attach this Authorization to the underlying session identified by the secret session identifier. This Authorization must be newly constructed or recently detach()'ed. The underlying session identified by the secretIdentifier must still be active (alive), or an UnauthorizedException will be thrown.
No other authorization nor authentication is needed to attach to the identified session. If you know the secret session identifier, it is assumed you are authorized to use the session. That's why the secret session identifier bytes must be treated as a valuable secret. Posession is equivalent to authorization.
If the HAS_SESSION_MULTIPROCESS bit is set in getCapabilities(), then a secret identifier will allow multiple processes to attach themselves to the same underlying session, thereby sharing authorizations and credentials for the lifetime of the session. Each process that wants to attach to the session must supply the correct secret identifier.
When the HAS_SESSION_MULTIPROCESS capability is not present, secret session identifiers do not work across process boundaries, even if the secret identifier is known.
- Throws: UnauthorizedException
- thrown when the session identified by the secret cannot be attached because it has vanished.
- Throws: IllegalArgumentException
- thrown when some malformation or structural error occurs.
- Throws: IllegalStateException
- thrown when this Authorization already represents an active session. That is, when this Authorization is not newly created or recently detach()'ed.
· attachPrivileged | Summary | Top |
public abstract void attachPrivileged()
Attach this Authorization to the same session used by execPrivileged() in the parent process. That session is only available to child processes executed by execPrivileged(), and needs no secret identifier. This capability allows the child process to exercise all the privileges of the parent, without ever sending a secret session identifier between the two processes.
If the current process is not a child by execPrivileged(), then this method fails.
- Throws: UnauthorizedException
- thrown when there is no privileged session to attach to.
- Throws: IllegalArgumentException
- thrown when some malformation or structural error occurs.
- Throws: IllegalStateException
- thrown when this Authorization already represents an active session. That is, when this Authorization is not newly created or recently detach()'ed.
· detach | Summary | Top |
public abstract void detach(boolean appliesToShared)
Detach this Authorization from any underlying session, acting on shared authorizations in the manner given by the boolean.
This method doesn't necessarily destroy the session or revoke its authorizations. The session will only be destroyed, and its authorizations revoked, if there are no remaining connections to the underlying session in any process. If another connection is still active in any process, then the session and its authorizations remain undisturbed by this Authorization's detach(). This more like decrementing a reference-count than asking that it be destroyed. In short, detach()'ing an Authorization won't necessarily revoke its granted authorizations and credentials. This is one reason why a session's secret identifier is such a valuable secret.
The only authorizations ever revoked are the ones for Privileges authorize()'d or preauthorize()'d in the underlying session. If you only used isAvailable() to check whether a Privilege is available, then detach() WILL NOT revoke any credential associated with that Privilege. This is one reason why you should not use isAvailable() to guard access to restricted areas of your program.
The boolean appliesToShared determines how shared authorizations are handled, if and when the session is destroyed. When the flag is true, shared authorizations are revoked. When the flag is false, they aren't. Unshared authorizations are always revoked when the session is destroyed.
Whether an authorization (a granted privilege) will be shared or not is determined by the policy rules defined for the named Privilege. That, however, is all defined below the level of the Authorization API. You can't easily tell whether a granted Privilege is shared or not.
The behavior of detach() is similar to how hard links work in the Unix file-system. There can be multiple links (references) to the same underlying file's contents (inode), and each filename, wherever it is, points to the same sequence of bytes on disk. Unlinking a filename (deleting a file) removes the link between the name and the inode, but the inode itself is only deleted when the last hard-link referring to it is unlinked. Anyone knowing the location of an existing hard-link, i.e. an accessible pathname, can establish another hard-link to the file's contents (inode). [Symlinks are completely different from hard links, and there is no analogy or similarity between symlinks and Authorization sessions.]
Depending on your application, you may not need to call detach(). When your program terminates, even unexpectedly, the system effectively calls detach(false) for you. However, you should detach() an Authorization when you're done using it, to ensure it is destroyed as soon as possible. How and when you detach() an Authorization is entirely dependent on the application.
After calling detach(), getPastGrantedPrivileges() will return an empty Enumeration, and will always return null from getPastGrantedDate(). This happens because there are no longer any past granted Privileges worth keeping.
A detach()'ed Authorization may have another session attached or established. You can call attach() or attachPrivileged() to attach the Authorization to a specific session. Or you can call one of the other methods that automatically makes a new session.
If this Authorization is not attached to a session when detach() is called, none is created and no error occurs. You can safely call detach() as many times as you want. It is idempotent.
- Throws: UnauthorizedException
- thrown when the underlying session cannot be properly released.
· release | Summary | Top |
public void release()
Detach this Authorization from any underlying session by calling detach(false). This is a convenience method.
· getPastGrantedPrivileges | Summary | Top |
public abstract Enumeration getPastGrantedPrivileges()
Return an Enumeration (possibly empty, but never null) representing all past Privileges granted by authorize() or preauthorize(). The Enumeration's nextElement() method returns a Privilege. Among other uses for the Privilege, you can call getPastGrantedDate() to find out when that Privilege was granted by this Authorization.
Only the Privileges actually granted by a call to authorize() or preauthorize() are enumerated. Privileges requested but not granted are not returned. Privileges passed only to isAvailable() are not returned. If execPrivilege() has to obtain authentication for itself, no Privilege representing that authentication will be present.
After a detach(), the list of past granted Privileges is cleared.
A Privilege that was granted in the past may have expired by the time this method is called. Thus, the Enumeration may contain Privileges which are not currently available. Conversely, a Privilege may not be present in the Enumeration but may be available. For example, if it is implied by another Privilege, or has been inherited from a shared session, or was granted in a session attached to by a known secret identifier.
This method DOES NOT create a new session if one is not attached. This method never throws an UnauthorizedException.
· getPastGrantedDate | Summary | Top |
public abstract Date getPastGrantedDate(Privilege privilege, int when)
If the given Privilege was previously granted, return a Date representing the timestamp of when that occurred. Privileges which were not overtly granted by authorize() or preauthorize() will always return null from this method. This doesn't necessarily mean the Privilege is unavailable, just that it was not overtly granted.
The value of 'when' should be one of the WHEN_XXX named constants.
This method DOES NOT create a new session if one is not attached. This method never throws an UnauthorizedException.
- Throws: IllegalArgumentException
- thrown when some malformation or structural error occurs, or if 'when' is an invalid value.
See Also: WHEN_EARLIEST, WHEN_LATEST
· keysGranted | Summary | Top |
protected Enumeration keysGranted()
A building-block for concrete imps. Return pastGranted's keys, which enumerates granted Privileges.
· whenGranted | Summary | Top |
protected Date whenGranted(Privilege privilege, int when)
A building-block for concrete imps. Return a Date representing when the Privilege was granted, or null if no Privilege granted or unknown when.
· addGranted | Summary | Top |
protected void addGranted(Privilege granted)
A building-block for concrete imps. A subclass will typically call this method each time a Privilege is granted, to record it as a past granted Privilege, along with appropriate timestamps. The timestamps are taken from System.currentTimeMillis(), which is presumed to be reasonably accurate.
This method is thread-safe, synchronized on the underlying pastGranted Hashtable.
· clearGranted | Summary | Top |
protected void clearGranted()
A building-block for concrete imps. Discard all past granted Privileges and their timestamps.
· makeExecPrivilege | Summary | Top |
public abstract Privilege makeExecPrivilege(String cmdName)
Make and return a Privilege representing the ability to execute a program with elevated privileges by way of execPrivileged(). A Privilege is created and returned, but it is not yet granted. The returned Privilege is the one that will be needed for execPrivileged() to succeed. You may pass the returned Privilege to preauthorize() before calling execPrivileged(). You may also call isAvailable() or authorize() with it.
If you don't authorize() or preauthorize() the Privilege, then execPrivileged() will authorize and authenticate for itself, interacting with the user as needed. This would block the current thread.
You don't need to call makeExecPrivilege() before calling execPrivileged(), but if control over user-interaction is important for your app's proper behavior, you should call makeExecPrivilege() and authorize() or preauthorize() first.
This method DOES NOT create a new session if one is not attached.
This method does not authorize, preauthorize, nor in any way grant or extend a privilege. It simply creates a Privilege identifying the desired ability to perform privileged-execution by way of execPrivileged().
The exact name, value, and flags of the returned Privilege are implementation-specific. That's why this method exists: so different concrete implementations are not limited to a specific Privilege name, value, or flags.
See Also: execPrivileged
· execPrivileged | Summary | Top |
public abstract Process execPrivileged(String[] progArray)
Execute a program as if run by a privileged user, or with temporarily elevated privileges. The exact meaning of "privileged user" or "elegate privileges" is implementation-dependent. If the execution privilege is denied, an UnauthorizedException is thrown and no program is executed. Some important characteristics of the resulting Process are described by bits in getCapabilities().
If the appropriate execution privilege os not already available or preauthorized, then the user may be interactively authenticated by this method, possibliy blocking the current thread. There is no way to prevent this except by authorizing or preauthorizing an appropriately constructed Privilege before calling this method. Since Privilege grants are constrained by time, session, and other limits, a past grant of the requisite Privilege is not indefinite.
If the authorization succeeds, a Privilege object representing the grant may or may not be added to the set of past granted Privileges. The choice is left to the implementation.
The String[] progArray represents the command to execute and the pre-parsed command-line parameters it receives. The convention is the same as that used by Runtime.exec(String[]). That is, the String at progArray[0] is a platform-dependent program-name, specified in a platform-dependent way, and the program's args are platform-dependent and command-specific.
For security reasons, this method may require the command String to be a fully qualified absolute pathname, in a platform-specific form, typically following File conventions. That decision is left to the implementation, which throws an UnauthorizedException if the command designated by progArray[0] is malformed or can't be found.
The returned Process may be limited or constrained in what you can do to it or with it. Many of its capabilities or constraints are described by bits in getCapabilities(). The Process will throw an IllegalArgumentException when one of its methods is called that isn't provided by the specific Process implementation. The stdin and stdout streams of the Process are typically provided, though there may be limitations on accessing or closing them. The getErrorStream() method may or may not be provided. The exitStatus() method may or may not be provided. The waitFor() method may or may not be provided. The destroy() method may or may not be provided.
- Throws: UnauthorizedException
- thrown when the necessary Privilege is not granted or preauthorized.
- Throws: IllegalArgumentException
- thrown when some malformation or structural error occurs.
See Also: Runtime.exec, getCapabilities, isCapable
· getSecretLength | Summary | Top |
public abstract int getSecretLength()
Return the non-zero length of a byte[] buffer that can hold a secret identifier. When getSecretIdentifier() returns a valid secret identifier, it will always be exactly this length. When attach() takes a secret identifier from a buffer, it will always take exactly this number of bytes. When you read a secret identifier's bytes from an I/O stream, it will always be this number of bytes.
The length of the necessary buffer is not a secret, though the actual length is implementation-dependent. An implementation determines what the proper length is, but it's always the same length for that implementation. If that weren't so, then processes reading the secret bytes wouldn't know how many bytes to read.
This method DOES NOT create a new session if one is not attached. This method throws no exceptions.
See Also: getSecretIdentifier, attach
· getSecretIdentifier | Summary | Top |
public abstract byte[] getSecretIdentifier()
Return a non-null byte[] holding a secret session identifier, or return a zero-length byte[] holding nothing. This method never returns null.
If this Authorization is attached to an active session, the session's secret identifier bytes are returned in a new byte[]. If no underlying session is attached, the returned byte[] will be zero-length, regardless of what getSecretLength() returns. Since no valid implementation has zero-length secret identifiers, you can tell whether a session is active or not by checking the returned array's length.
No underlying session has true long-term persistence, so neither does its secret identifier. That is, all secret identifiers are transitory. Once the session it identifies is destroyed, a secret identifier has no value. During its lifetime, though, a session's secret identifier may be a valuable secret. An active session is bounded by host, process, login, and other limits determined by the concrete implementation. Typically, you can't store the secret identifier and then use it later, unless the session itself remains active in some process. (See detach()). Long-lived sessions that remain active across multiple processes pose added security risks, so even if you invent a way to keep the session alive, you probably shouldn't do it.
Knowing a session's secret identifier is not the same as being attached to that session. The secret identifier is at most a kind of "passcard" that allows attachment to the session, but only if the session still exists and is accessible from the current process and host-machine. The secret identifier is not a serialized representation of the session itself or its contents.
For example, if you have a unique (unshared) session and get its secret identifier bytes, then detach() the Authorization, the session will disappear because there was only one attached connection. Subsequent attempts to attach() to the session using its secret identifier will all fail, even though you still know the secret identifier. See the detach() method for an analogy with hard-links in the Unix filesystem.
If the HAS_SESSION_MULTIPROCESS capability is present, then the secret identifier will uniquely identify the session across multiple processes, and allow attachment.
A secret identifier is presumed to be unique to a session, though it may not be unique to an Authorization instance. That is, more than one Authorization can refer to the same session. You could use a secret identifier to identify a session, but since it's a secret you must handle it carefully. It's much safer to use getPublicIdentifier(), and it has the advantage of being a String, so comparison is more easily done than with a byte[].
IMPORTANT -- THE RETURNED DATA IS A VALUABLE SECRET. Any process that can obtain (or correctly guess) the secret session identifier may be able to gain access to the credentials and granted privileges of the underlying session. You should erase the secret bytes immediately after using them, preferably in a try/finally block that ensures erasure. ERASE THE SECRET WHEN DONE -- DON'T JUST LET THE ARRAY BE GC'ED.
- Throws: UnauthorizedException
- thrown when the session identifier cannot be placed in the buffer.
- Throws: IllegalArgumentException
- thrown when some malformation or structural error occurs.
See Also: getPublicIdentifier, attach, detach
· getPublicIdentifier | Summary | Top |
public String getPublicIdentifier()
Return a distinctive public (non-secret) identifier based on the underlying session's unique secret identifier, but obscured in such a way that the secret itself is not discernible, nor guessable by any means except brute force. In short, return a "fingerprint" of the session identifier, without revealing any secrets. Typically, this is accomplished by calculating a cryptographic hash or message-digest using the secret identifier's bytes, possibly including other information.
The length of the public identifier is not related to the length of the secret identifier. Public identifier length is related to the hash or message-digest algorithm. The default hash algorithm is "MD5", which returns a 16-byte result regardless of how many bytes are hashed. Those bytes are turned into a String in a specific form, and that String is the public identifier.
If this Authorization is not attached to any underlying session, an implementation must always return the non-null empty String: "". That is, the public identifier of all unattached Authorizations is the same (""), even when the concrete Authorization imps differ, or when getPublicIdentifier() is overridden or uses a different digest algorithm. Among other things, this lets you test whether an Authorization is attached to a session simply by testing its fingerprint.
Another use for this method is to give programs a way to test when two Authorizations refer to the same session, without directly comparing the secret identifiers. Or conversely, programs may need to distinguish Authorizations attached to different sessions. Making this distinction is not the same as implementing the equals() method in Authorization. Well, it could be, but it would be insufficient, since programs might need to identify matching sessions across processes or hosts, and that would be impossible with equals() alone. Furthermore, Java programs might need to identify sessions used by other programs not written in Java.
This default implementation uses an "MD5" MessageDigest to calculate the fingerprint. It calls the public method makeFingerprint() to make the actual fingerprint bytes from the secret, then the protected method formFingerprint() to turn those bytes into a String.
- Throws: UnauthorizedException
- thrown when a MessageDigest instance can't be obtained.
See Also: makeFingerprint, formFingerprint
· makeFingerprint | Summary | Top |
public byte[] makeFingerprint(String algorithmName)
This method is the foundation for getPublicIdentifier(). It accepts any message-digest algorithm name, for flexibility in creating public identifiers or session fingerprints.
If this Authorization is not attached to a session, null is returned. This happens regardless of the concrete Authorization imp, or the given algorithmName.
This default implementation uses a java.security.MessageDigest to calculate the fingerprint. No provider-name is specified to MessageDigest.getInstance(), so any available MessageDigest implementation will be used. If the requested algorithm is not available, this method throws an UnauthorizedException. If the algorithm is available, the fingerprint is calculated as follows:
This method handles the secret identifier securely, using a try/finally block to ensure the secret bytes are always erased.
- The MessageDigest is initialized via reset().
- The MessageDigest is update()'d with the bytes of the secret identifier, in sequential order.
- The MessageDigest is update()'d with the length of the secret (measured in bytes), as a big-endian 32-bit integer (i.e. as a typical Java 'int').
- The raw digest bytes are calculated by calling digest().
- The secret identifier's bytes, if any, are erased to 0's.
- The digest byte-array is returned (it may be null ).
- Throws: UnauthorizedException
- thrown when a MessageDigest can't be instantiated, or when the secret identifier for the session can't be determined.
See Also: getSecretIdentifier, getPublicIdentifier
· formFingerprint | Summary | Top |
protected String formFingerprint(String algorithmName, byte[] digest)
This method is called by getPublicIdentifer() to turn the binary bytes of a message-digest into a human-readable String form. This is a separate method to simplify changing the form of the public-identifier String without having to replace all the secret-handling code in makeFingerprint(). It has protected scope because it's typically not useful for others to call it.
If the given byte array is null or zero-length, the returned String is always the empty String "". This is true regardless of the concrete Authorization imp, or the given algorithmName.
This method does not instantiate or use a MessageDigest. It only uses the provided algorithmName to build a String.
The digest bytes are converted into a String of this form:
algorithmName:hexwhere algorithmName is the given String arg, and hex is the upper-case hex representation of the array's bytes. There is a literal ":" between the algorithmName and the hex parts.In Java, all Strings consist of Unicode characters, but the above algorithm will always produce Strings composed entirely of characters in the US-ASCII charset, with no white-space or control characters unless algorithmName contains them.
See Also: getPublicIdentifier, makeFingerprint
All Packages This Package Class Hierarchy Class Search IndexFreshly brewed Java API Documentation automatically generated with polardoc Version 1.0.7