I too believe that Authorization is not served well by Subject, at all. The
reason being that it is not "Role" oriented, but rather "permission" oriented
and the "permission set" is not always the right "mask" to set in front of a
decision process, without a lot of permissions that soon become confusing to
manage without some sort of structured view such as a simple "database" or
"collection view".
What I did, was create a mechanism that uses "XML" to specify what is needed for
each method in an interface. I've posted about this before, and have not really
received much feedback either way about it, so I'll hang it out on a stick again.
Basically, think of these steps as the process.
1. Design the service interface.
2. Take each method, and decide what Roles use those methods and note the
roles in a list.
3. Decide what types of objects will need to be controlled by role based
access.
4. Design permissions that use the values of arguments to the methods
to segregate access based on role as needed.
The basics are specified as shown here.
<methodaccess>
<control>
<principals>
<principal type="users" memberof="groups" admin="yes"/>
<principal type="groups" admin="no"/>
</principals>
<object type="director" access="update,read,download"
permission="DirectorAccessPermission"/>
<object type="config" access="update,read"
permission="ConfigAccessPermission"/>
<object type="database" access="update,read"
permission="DatabaseAccessPermission"/>
</control>
...
</methodaccess>
This stuff is all stored and referenced from some backing store, such as a
database, but you can "create" the appropriate backing store through an API.
The above will cause code to be created that will populate the backing store
with the shown items to "initialize" the store.
Here's a method definition for a method that requires "config" role access. The
<limit> entries specify the type="config" attribute that says thats the
role/permission. The access="" attribute says what type of access is required,
and the <create> says that we should create backing store specified entries use
regSet.getName() as the key in the backing store for access to be granted.
Thus, initially, a user would be given administrative access, and through the
application UI, calling this method, would cause the entries to be created that
other users could then be given role based access to by granting them so.
<method return="void" name="setRegSet" qualifiers="public">
<descr>
Security definition for setRegSet() method
</descr>
<security>
<limit access="update" type="config" inst="regSet" arg="regset"
via="arg" method="getName"/>
<create access="update" type="config" inst="regSet"
arg="regset" via="arg" method="getName"/>
</security>
<args>
<arg name="regset" type="com.cytetech.dcm.data.RegSet"
descr=""/>
</args>
<exceptions>
<throws name="java.sql.SQLException" descr=""/>
<throws name="java.rmi.RemoteException" descr=""/>
</exceptions>
</method>
There is a complete admin UI panel set that you tie to the backing store, and
the tooling runs across this XML and generates a Java class which you then just
instantiate with an instance of the original class, and then you export this one
instead of the original one. The generated class then completely implements
your authorization scheme, independent of Java Policy, so that authorization is
about application items and not about "java policy".
It's a "big bunch of code", so it's not "simple to use" without some learning.
It's also probably not "perfect" for your needs. But, I've been using various
versions of this code since JDK1.1 and JDK1.3 before JAAS hit the scenes. I
tried desperately to keep JAAS from just being about Java Policy controls, and
to get "Real Authentication" to happen. Alas, it never did. So, I also use JNI
code that I put together to call into PAM on Linux for Subject authentication.
The sheer complexity of this kind of thing is what troubles me the most about
Jini security. It really becomes a giant ordeal to get "right" let alone "made
simple".
Gregg Wonderly
On 8/9/2011 10:58 AM, Greg Trasuk wrote:
On Tue, 2011-08-09 at 02:53, Peter wrote:
Following up on recent discussions about security.
Java, River / Jini Security features are advanced programming concepts.
You need security policies, need to know what permissions each codebase
requires to function. A key server is essential, along with user Subjects and
Principals (including preserving the SubjectDomainCombiner accross privileged
calls. Then you've got Proxy trust, verification and dynamic grants.
I've thought previously about having separate releases, one for private
networks, the other for untrusted networks. Leading me to consider modularity,
to avoid forking, that, classloader issues and codebase annotation loss. But
modularity appears to have stalled. A lot of the code I'm writing is in
different branches, I'm not great at merging, and will be time poor soon, so
I'm concentrating on wrapping up my recent security work.
I don't see separate releases solving anything. The security setup
should just be a matter of selecting a different Configuration file,
depending on what level and type of transport security and
confidentiality you want. I'd picture supplying a minimal-security
configuration and a maximal-lockdown config for Kerberos and SSL.
Does anyone have any suggestions for annotations? So developers can weave in
security later, allowing them to get up and running with River in a local
network first, then learn security later?
Some random thoughts:
- Security can be decomposed into
- Authentication
- Authorization
- Integrity of communications
- Confidentiality of communications
- Jeri does a great job with Authentication (can use Kerberos or X509
certs), Cinfidentiality and Integrity (through SSL, https, Kerberos
endpoints).
- The SecurityPolicy model was originally intended to support
codebase-based security (i.e. permissions are applied to a
ProtectionDomain associated with the source of the code).
- JAAS extension glued on Subject-based decisions to the SecurityPolicy
model after-the-fact.
I've been gradually becoming convinced that the JAAS security model
(i.e. SubjectDomainCombiner etc) is not very good for subject-based
authorization. The basic business need for a service is to answer the
question "Is Bob allowed to place a purchase order?", where Bob's
authorization might be subject to change over time, or might be subject
to additional business rules. Seems like in order to enforce that
decision using the SecurityPolicy model, we end up needing elaborate
constructs (e.g. revokable permissions, remote policy files,
classloader/protection domain magic, dynamic policy lookup, etc).
I can't help wondering if the deployer's life is made easier if we just
say "Authorization is the service's problem" for now. Possibly we could
design an AuthorizationService that the service implementor could
delegate to for that decision. At least then, supporting a cached,
dynamic authorization policy (for service-,ethod-level authorization)
wouldn't need so much digging around at low levels. The
DynamicPolicyProvider already allows for assigning limited system
privileges to a proxy class.
Thoughts?
Example: an annotation and the boilerplate code that needs to be weaved in by
an annotation processor.
EJB3 includes @RolesAllowed. I wouldn't want to couple to the Java EE
API, but something similar would work. Then it wouldn't be a major
trick to create a delegating proxy that checked the required security
roles.
Alternately, just make the client subject available and the app
developer could use something like Spring Security to implement the
method-level authorization. Again I wouldn't want to couple River to
Spring in any way, but the required liaison classes could be in a
separate support package.
Cheers,
Peter.