You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2013/01/04 16:14:59 UTC
[1/6] git commit: ISIS-290: first steps towards a shiro impl
ISIS-290: first steps towards a shiro impl
Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/95c0b553
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/95c0b553
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/95c0b553
Branch: refs/heads/master
Commit: 95c0b553b7da00724db232e58d005c1269b42487
Parents: 24563ea
Author: Dan Haywood <da...@apache.org>
Authored: Sun Dec 30 18:09:26 2012 +0000
Committer: Dan Haywood <da...@apache.org>
Committed: Fri Jan 4 09:20:05 2013 +0000
----------------------------------------------------------------------
component/security/shiro/NOTICE | 7 +
component/security/shiro/pom.xml | 133 ++++++++
.../appended-resources/supplemental-models.xml | 106 +++++++
.../shiro/ShiroAuthenticatorOrAuthorizor.java | 234 +++++++++++++++
.../apache/isis/security/shiro/ShiroConstants.java | 36 +++
.../ShiroAuthenticationManagerInstaller.java | 44 +++
.../ShiroAuthorizationManagerInstaller.java | 40 +++
component/security/shiro/src/site/apt/index.apt | 44 +++
component/security/shiro/src/site/apt/jottings.apt | 24 ++
component/security/shiro/src/site/site.xml | 41 +++
.../security/shiro/ShiroAuthenticatorTester.java | 149 +++++++++
.../shiro/authorization/ShiroAuthorizorTester.java | 150 +++++++++
.../security/shiro/src/test/resources/shiro.ini | 58 ++++
13 files changed, 1066 insertions(+), 0 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/isis/blob/95c0b553/component/security/shiro/NOTICE
----------------------------------------------------------------------
diff --git a/component/security/shiro/NOTICE b/component/security/shiro/NOTICE
new file mode 100644
index 0000000..0a76071
--- /dev/null
+++ b/component/security/shiro/NOTICE
@@ -0,0 +1,7 @@
+Apache Isis
+Copyright 2010-2012 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+
http://git-wip-us.apache.org/repos/asf/isis/blob/95c0b553/component/security/shiro/pom.xml
----------------------------------------------------------------------
diff --git a/component/security/shiro/pom.xml b/component/security/shiro/pom.xml
new file mode 100644
index 0000000..ca2d9e8
--- /dev/null
+++ b/component/security/shiro/pom.xml
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.isis.core</groupId>
+ <artifactId>isis</artifactId>
+ <version>1.0.1-SNAPSHOT</version>
+ <relativePath>../../../core/pom.xml</relativePath>
+ </parent>
+
+ <groupId>org.apache.isis.security</groupId>
+ <artifactId>isis-security-shiro</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+
+ <name>Isis Shiro Security</name>
+
+ <properties>
+ <siteBaseDir>.</siteBaseDir>
+ <relativeUrl/>
+ <shiro.version>1.2.1</shiro.version>
+ </properties>
+
+ <!-- used in Site generation for relative references. -->
+ <url>http://isis.apache.org/${relativeUrl}</url>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <!-- Apache Release Audit Tool -->
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <version>0.8</version>
+ <configuration>
+ <excludes>
+ <!--
+ overriding inherited excludes from oia.core:isis
+ with a more specific set for this component
+ -->
+ <exclude>**/target/**</exclude>
+ <exclude>**/target-ide/**</exclude>
+
+ <exclude>**/*.project</exclude>
+ <exclude>**/.classpath</exclude>
+ <exclude>**/.settings/**</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-project-info-reports-plugin</artifactId>
+ <version>${maven-project-info-reports-plugin}</version>
+ <inherited>false</inherited>
+ <configuration>
+ <dependencyLocationsEnabled>false</dependencyLocationsEnabled>
+ </configuration>
+ <reportSets>
+ <reportSet>
+ <inherited>false</inherited>
+ <reports>
+ <report>dependencies</report>
+ <report>dependency-convergence</report>
+ <report>plugins</report>
+ <report>summary</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ </plugin>
+ </plugins>
+ </reporting>
+
+ <dependencyManagement>
+ <!-- for benefit of application developers, using scope=import -->
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.isis.security</groupId>
+ <artifactId>isis-security-shiro</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.isis.core</groupId>
+ <artifactId>isis-core-runtime</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.isis.core</groupId>
+ <artifactId>isis-core-unittestsupport</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.isis.core</groupId>
+ <artifactId>isis-core-runtime</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.shiro</groupId>
+ <artifactId>shiro-core</artifactId>
+ <version>${shiro.version}</version>
+ </dependency>
+
+
+ </dependencies>
+</project>
http://git-wip-us.apache.org/repos/asf/isis/blob/95c0b553/component/security/shiro/src/main/appended-resources/supplemental-models.xml
----------------------------------------------------------------------
diff --git a/component/security/shiro/src/main/appended-resources/supplemental-models.xml b/component/security/shiro/src/main/appended-resources/supplemental-models.xml
new file mode 100644
index 0000000..ecd3906
--- /dev/null
+++ b/component/security/shiro/src/main/appended-resources/supplemental-models.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor
+ license agreements. See the NOTICE file distributed with this work for additional
+ information regarding copyright ownership. The ASF licenses this file to
+ you under the Apache License, Version 2.0 (the "License"); you may not use
+ this file except in compliance with the License. You may obtain a copy of
+ the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required
+ by applicable law or agreed to in writing, software distributed under the
+ License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
+ OF ANY KIND, either express or implied. See the License for the specific
+ language governing permissions and limitations under the License. -->
+<supplementalDataModels xmlns="http://maven.apache.org/supplemental-model/1.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/supplemental-model/1.0.0 http://maven.apache.org/xsd/supplemental-model-1.0.0.xsd">
+
+ <supplement>
+ <project>
+ <groupId>aopalliance</groupId>
+ <artifactId>aopalliance</artifactId>
+ <version>1.0</version>
+ <licenses>
+ <license>
+ <name>Public Domain</name>
+ </license>
+ </licenses>
+ </project>
+ </supplement>
+
+ <supplement>
+ <!-- not quite sure why licenses:download-license flags this, since license info seems to be in its POM -->
+ <project>
+ <groupId>org.datanucleus</groupId>
+ <artifactId>datanucleus-jodatime</artifactId>
+ <version>3.1.1</version>
+ <licenses>
+ <license>
+ <name>The Apache Software License, Version 2.0</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+ </license>
+ </licenses>
+ </project>
+ </supplement>
+
+ <supplement>
+ <project>
+ <groupId>org.scannotation</groupId>
+ <artifactId>scannotation</artifactId>
+ <version>1.0.3</version>
+ <licenses>
+ <license>
+ <name>The Apache Software License, Version 2.0</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+ </project>
+ </supplement>
+
+ <supplement>
+ <project>
+ <groupId>dom4j</groupId>
+ <artifactId>dom4j</artifactId>
+ <version>1.6.1</version>
+ <licenses>
+ <license>
+ <name>BSD License</name>
+ <url>http://dom4j.sourceforge.net/dom4j-1.6.1/license.html</url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+ </project>
+ </supplement>
+
+ <supplement>
+ <project>
+ <groupId>net.jcip</groupId>
+ <artifactId>jcip-annotations</artifactId>
+ <version>1.0</version>
+ <licenses>
+ <license>
+ <name>Creative Commons Attribution 2.5 License</name>
+ <url>http://creativecommons.org/licenses/by/2.5/</url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+ </project>
+ </supplement>
+
+
+ <supplement>
+ <project>
+ <groupId>xalan</groupId>
+ <artifactId>xalan</artifactId>
+ <version>2.7.0</version>
+ <licenses>
+ <license>
+ <name>The Apache Software License, Version 2.0</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+ </project>
+ </supplement>
+
+
+</supplementalDataModels>
http://git-wip-us.apache.org/repos/asf/isis/blob/95c0b553/component/security/shiro/src/main/java/org/apache/isis/security/shiro/ShiroAuthenticatorOrAuthorizor.java
----------------------------------------------------------------------
diff --git a/component/security/shiro/src/main/java/org/apache/isis/security/shiro/ShiroAuthenticatorOrAuthorizor.java b/component/security/shiro/src/main/java/org/apache/isis/security/shiro/ShiroAuthenticatorOrAuthorizor.java
new file mode 100644
index 0000000..c31e663
--- /dev/null
+++ b/component/security/shiro/src/main/java/org/apache/isis/security/shiro/ShiroAuthenticatorOrAuthorizor.java
@@ -0,0 +1,234 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.security.shiro;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.isis.applib.Identifier;
+import org.apache.isis.core.commons.authentication.AuthenticationSession;
+import org.apache.isis.core.commons.config.IsisConfiguration;
+import org.apache.isis.core.runtime.authentication.AuthenticationManagerInstaller;
+import org.apache.isis.core.runtime.authentication.AuthenticationRequest;
+import org.apache.isis.core.runtime.authentication.AuthenticationRequestPassword;
+import org.apache.isis.core.runtime.authentication.standard.Authenticator;
+import org.apache.isis.core.runtime.authentication.standard.SimpleSession;
+import org.apache.isis.core.runtime.authorization.AuthorizationManagerInstaller;
+import org.apache.isis.core.runtime.authorization.standard.Authorizor;
+import org.apache.log4j.Logger;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.UnavailableSecurityManagerException;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.ExcessiveAttemptsException;
+import org.apache.shiro.authc.IncorrectCredentialsException;
+import org.apache.shiro.authc.LockedAccountException;
+import org.apache.shiro.authc.UnknownAccountException;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.config.IniSecurityManagerFactory;
+import org.apache.shiro.mgt.DefaultSecurityManager;
+import org.apache.shiro.mgt.RealmSecurityManager;
+import org.apache.shiro.mgt.SecurityManager;
+import org.apache.shiro.realm.Realm;
+import org.apache.shiro.subject.Subject;
+import org.apache.shiro.util.Factory;
+
+import com.google.common.collect.Lists;
+
+/**
+ * If Shiro is configured for both {@link AuthenticationManagerInstaller authentication} and
+ * {@link AuthorizationManagerInstaller authorization} (as recommended), then this class is
+ * instantiated twice, once in the role of {@link Authenticator} and once in the role of the {@link Authorizor}.
+ *
+ * <p>
+ * However, although there are two objects, they are set up to share the same {@link SecurityManager Shiro SecurityManager}.
+ */
+public class ShiroAuthenticatorOrAuthorizor implements Authenticator, Authorizor {
+
+ private static final Logger LOG = Logger.getLogger(ShiroAuthenticatorOrAuthorizor.class);
+
+ private final IsisConfiguration configuration;
+
+ private SecurityManager shiroSecurityManager;
+ /**
+ * Downcast of {@link #shiroSecurityManager} (if of this type).
+ */
+ private RealmSecurityManager realmSecurityManager;
+
+ // //////////////////////////////////////////////////////
+ // constructor
+ // //////////////////////////////////////////////////////
+
+ public ShiroAuthenticatorOrAuthorizor(final IsisConfiguration configuration) {
+ this.configuration = configuration;
+ }
+
+ // //////////////////////////////////////////////////////
+ // init, shutdown
+ // //////////////////////////////////////////////////////
+
+ @Override
+ public void init() {
+ this.shiroSecurityManager = getSecurityManager(configuration);
+ if(shiroSecurityManager instanceof RealmSecurityManager) {
+ this.realmSecurityManager = (RealmSecurityManager) shiroSecurityManager;
+ }
+ }
+
+ /**
+ * The {@link SecurityManager} is shared between both the {@link Authenticator} and the {@link Authorizor}
+ * (if shiro is configured for both components).
+ */
+ private static synchronized SecurityManager getSecurityManager(final IsisConfiguration configuration) {
+ try {
+ return (DefaultSecurityManager) SecurityUtils.getSecurityManager();
+ } catch(UnavailableSecurityManagerException ex) {
+ Factory<SecurityManager> factory = new IniSecurityManagerFactory(configuration.getString("isis.security.shiro.iniLocation", "classpath:shiro.ini"));
+ SecurityManager securityManager = factory.getInstance();
+ SecurityUtils.setSecurityManager(securityManager);
+ return securityManager;
+ }
+ }
+
+ @Override
+ public void shutdown() {
+ //
+ }
+
+ // //////////////////////////////////////////////////////
+ // Authenticator API
+ // //////////////////////////////////////////////////////
+
+ @Override
+ public final boolean canAuthenticate(final Class<? extends AuthenticationRequest> authenticationRequestClass) {
+ return AuthenticationRequestPassword.class.isAssignableFrom(authenticationRequestClass);
+ }
+
+ @Override
+ public AuthenticationSession authenticate(final AuthenticationRequest request, final String code) {
+ final AuthenticationToken token = asAuthenticationToken(request);
+
+ Subject currentUser = SecurityUtils.getSubject();
+ if(currentUser.isAuthenticated()) {
+ // TODO: verify the code passed in that this session is still alive?
+
+ // TODO: perhaps we should cache Isis' AuthenticationSession inside the Shiro Session, and
+ // just retrieve it?
+
+ // for now, just log them out.
+ currentUser.logout();
+ }
+ try {
+ currentUser.login(token);
+ } catch ( UnknownAccountException uae ) {
+ LOG.debug("Unable to authenticate", uae);
+ return null;
+ } catch ( IncorrectCredentialsException ice ) {
+ LOG.debug("Unable to authenticate", ice);
+ return null;
+ } catch ( LockedAccountException lae ) {
+ LOG.info("Unable to authenticate", lae);
+ return null;
+ } catch ( ExcessiveAttemptsException eae ) {
+ LOG.info("Unable to authenticate", eae);
+ return null;
+ } catch ( AuthenticationException ae ) {
+ LOG.error("Unable to authenticate", ae);
+ return null;
+ }
+
+ List<String> roles = getRoles(token);
+
+ return new SimpleSession(request.getName(), roles, code);
+ }
+
+ private List<String> getRoles(final AuthenticationToken token) {
+ if(realmSecurityManager == null) {
+ return Collections.emptyList();
+ }
+ final List<String> roles = Lists.newArrayList();
+ final Collection<Realm> realms = realmSecurityManager.getRealms();
+ for (final Realm realm : realms) {
+ if(realm.supports(token)) {
+ continue;
+ }
+ final AuthenticationInfo authenticationInfo = realm.getAuthenticationInfo(token);
+ if(authenticationInfo instanceof AuthorizationInfo) {
+ final AuthorizationInfo authorizationInfo = (AuthorizationInfo) authenticationInfo;
+ final Collection<String> realmRoles = authorizationInfo.getRoles();
+ for (final String role : realmRoles) {
+ roles.add(realm.getName() + ":" + role);
+ }
+ }
+ }
+ return roles;
+ }
+
+ private static AuthenticationToken asAuthenticationToken(final AuthenticationRequest request) {
+ final AuthenticationRequestPassword passwordRequest = (AuthenticationRequestPassword) request;
+ final String username = passwordRequest.getName();
+ final String password = passwordRequest.getPassword();
+
+ return new UsernamePasswordToken(username, password);
+ }
+
+
+ // //////////////////////////////////////////////////////
+ // Authorizor API
+ // //////////////////////////////////////////////////////
+
+ @Override
+ public boolean isVisibleInAnyRole(Identifier identifier) {
+ return false;
+ }
+
+ @Override
+ public boolean isUsableInAnyRole(Identifier identifier) {
+ return false;
+ }
+
+ @Override
+ public boolean isVisibleInRole(String role, Identifier identifier) {
+ if(shiroSecurityManager instanceof RealmSecurityManager) {
+
+ }
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean isUsableInRole(String role, Identifier identifier) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+
+ // //////////////////////////////////////////////////////
+ // Injected (via constructor)
+ // //////////////////////////////////////////////////////
+
+ public IsisConfiguration getConfiguration() {
+ return configuration;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/95c0b553/component/security/shiro/src/main/java/org/apache/isis/security/shiro/ShiroConstants.java
----------------------------------------------------------------------
diff --git a/component/security/shiro/src/main/java/org/apache/isis/security/shiro/ShiroConstants.java b/component/security/shiro/src/main/java/org/apache/isis/security/shiro/ShiroConstants.java
new file mode 100644
index 0000000..d5d0d51
--- /dev/null
+++ b/component/security/shiro/src/main/java/org/apache/isis/security/shiro/ShiroConstants.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.security.shiro;
+
+import org.apache.isis.core.commons.config.ConfigurationConstants;
+import org.apache.isis.core.runtime.authentication.AuthenticationManagerInstaller;
+import org.apache.isis.core.runtime.authorization.AuthorizationManagerInstaller;
+import org.apache.isis.security.shiro.authentication.ShiroAuthenticationManagerInstaller;
+import org.apache.isis.security.shiro.authorization.ShiroAuthorizationManagerInstaller;
+
+public final class ShiroConstants {
+
+ public static final String ROOT_AUTHENTICATION = ConfigurationConstants.ROOT + AuthenticationManagerInstaller.TYPE + "." + ShiroAuthenticationManagerInstaller.NAME + ".";
+ private static final String ROOT_AUTHORIZATION = ConfigurationConstants.ROOT + AuthorizationManagerInstaller.TYPE + "." + ShiroAuthorizationManagerInstaller.NAME + ".";
+
+ private ShiroConstants() {
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/95c0b553/component/security/shiro/src/main/java/org/apache/isis/security/shiro/authentication/ShiroAuthenticationManagerInstaller.java
----------------------------------------------------------------------
diff --git a/component/security/shiro/src/main/java/org/apache/isis/security/shiro/authentication/ShiroAuthenticationManagerInstaller.java b/component/security/shiro/src/main/java/org/apache/isis/security/shiro/authentication/ShiroAuthenticationManagerInstaller.java
new file mode 100644
index 0000000..b462614
--- /dev/null
+++ b/component/security/shiro/src/main/java/org/apache/isis/security/shiro/authentication/ShiroAuthenticationManagerInstaller.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.security.shiro.authentication;
+
+import java.util.List;
+
+import com.google.common.collect.Lists;
+
+import org.apache.isis.core.commons.config.IsisConfiguration;
+import org.apache.isis.core.runtime.authentication.AuthenticationManagerStandardInstallerAbstractForDfltRuntime;
+import org.apache.isis.core.runtime.authentication.standard.Authenticator;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.security.shiro.ShiroAuthenticatorOrAuthorizor;
+
+public class ShiroAuthenticationManagerInstaller extends AuthenticationManagerStandardInstallerAbstractForDfltRuntime {
+
+ public static String NAME = "shiro";
+
+ public ShiroAuthenticationManagerInstaller() {
+ super(NAME);
+ }
+
+ @Override
+ protected List<Authenticator> createAuthenticators(final IsisConfiguration configuration) {
+ return Lists.<Authenticator> newArrayList(new ShiroAuthenticatorOrAuthorizor(configuration));
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/95c0b553/component/security/shiro/src/main/java/org/apache/isis/security/shiro/authorization/ShiroAuthorizationManagerInstaller.java
----------------------------------------------------------------------
diff --git a/component/security/shiro/src/main/java/org/apache/isis/security/shiro/authorization/ShiroAuthorizationManagerInstaller.java b/component/security/shiro/src/main/java/org/apache/isis/security/shiro/authorization/ShiroAuthorizationManagerInstaller.java
new file mode 100644
index 0000000..2858813
--- /dev/null
+++ b/component/security/shiro/src/main/java/org/apache/isis/security/shiro/authorization/ShiroAuthorizationManagerInstaller.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.security.shiro.authorization;
+
+import org.apache.isis.core.commons.config.IsisConfiguration;
+import org.apache.isis.core.runtime.authorization.standard.AuthorizationManagerStandardInstallerAbstract;
+import org.apache.isis.core.runtime.authorization.standard.Authorizor;
+import org.apache.isis.security.shiro.ShiroAuthenticatorOrAuthorizor;
+
+public class ShiroAuthorizationManagerInstaller extends AuthorizationManagerStandardInstallerAbstract {
+
+ public static String NAME = "shiro";
+
+ public ShiroAuthorizationManagerInstaller() {
+ super(NAME);
+ }
+
+ @Override
+ protected Authorizor createAuthorizor(final IsisConfiguration configuration) {
+ return new ShiroAuthenticatorOrAuthorizor(configuration);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/95c0b553/component/security/shiro/src/site/apt/index.apt
----------------------------------------------------------------------
diff --git a/component/security/shiro/src/site/apt/index.apt b/component/security/shiro/src/site/apt/index.apt
new file mode 100644
index 0000000..8978117
--- /dev/null
+++ b/component/security/shiro/src/site/apt/index.apt
@@ -0,0 +1,44 @@
+~~ Licensed to the Apache Software Foundation (ASF) under one
+~~ or more contributor license agreements. See the NOTICE file
+~~ distributed with this work for additional information
+~~ regarding copyright ownership. The ASF licenses this file
+~~ to you under the Apache License, Version 2.0 (the
+~~ "License"); you may not use this file except in compliance
+~~ with the License. You may obtain a copy of the License at
+~~
+~~ http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing,
+~~ software distributed under the License is distributed on an
+~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+~~ KIND, either express or implied. See the License for the
+~~ specific language governing permissions and limitations
+~~ under the License.
+
+
+
+Security LDAP Implementation
+
+ The <ldap security> module provides an implementation of Isis' authentication and
+ authorization APIs where credentials are stored in a well-known LDAP server.
+
+ This makes the LDAP security implementation suitable for deployment where an
+ LDAP exists. Optionally it may be combined with other implementations (for example
+ the authorization might be performed using the file-based implementation).
+
+ See the security
+ {{{../docbkx/html/guide/isis-security.html}HTML}} or
+ {{{../docbkx/pdf/isis-security.pdf}PDF}} documentation for more detail.
+
+Alternatives
+
+ Alternatives include:
+
+ * the {{{../dflt/index.html}default}} (no-op) security implementation, for prototyping use only
+
+ * the {{{../file/index.html}file-based}} security (reading from simple flat files)
+
+ * the {{{../sql/index.html}SQL}} security (reading from simple SQL tables)
+
+ []
+
http://git-wip-us.apache.org/repos/asf/isis/blob/95c0b553/component/security/shiro/src/site/apt/jottings.apt
----------------------------------------------------------------------
diff --git a/component/security/shiro/src/site/apt/jottings.apt b/component/security/shiro/src/site/apt/jottings.apt
new file mode 100644
index 0000000..c5d1200
--- /dev/null
+++ b/component/security/shiro/src/site/apt/jottings.apt
@@ -0,0 +1,24 @@
+~~ Licensed to the Apache Software Foundation (ASF) under one
+~~ or more contributor license agreements. See the NOTICE file
+~~ distributed with this work for additional information
+~~ regarding copyright ownership. The ASF licenses this file
+~~ to you under the Apache License, Version 2.0 (the
+~~ "License"); you may not use this file except in compliance
+~~ with the License. You may obtain a copy of the License at
+~~
+~~ http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing,
+~~ software distributed under the License is distributed on an
+~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+~~ KIND, either express or implied. See the License for the
+~~ specific language governing permissions and limitations
+~~ under the License.
+
+
+
+Jottings
+
+ This page is to capture any random jottings relating to this module prior
+ to being moved into formal documentation.
+
http://git-wip-us.apache.org/repos/asf/isis/blob/95c0b553/component/security/shiro/src/site/site.xml
----------------------------------------------------------------------
diff --git a/component/security/shiro/src/site/site.xml b/component/security/shiro/src/site/site.xml
new file mode 100644
index 0000000..1f465f4
--- /dev/null
+++ b/component/security/shiro/src/site/site.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<project>
+
+ <body>
+ <breadcrumbs>
+ <item name="LDAP" href="index.html"/>
+ </breadcrumbs>
+
+ <menu name="LDAP Security">
+ <item name="About" href="index.html" />
+ <item name="Jottings" href="jottings.html" />
+ </menu>
+
+ <menu name="Security Modules">
+ <item name="Default (No-op)" href="../dflt/index.html" />
+ <item name="File" href="../file/index.html" />
+ <item name="LDAP" href="../ldap/index.html" />
+ <item name="SQL" href="../sql/index.html" />
+ </menu>
+
+ <menu name="Maven Reports" ref="reports" />
+ </body>
+</project>
http://git-wip-us.apache.org/repos/asf/isis/blob/95c0b553/component/security/shiro/src/test/java/org/apache/isis/security/shiro/ShiroAuthenticatorTester.java
----------------------------------------------------------------------
diff --git a/component/security/shiro/src/test/java/org/apache/isis/security/shiro/ShiroAuthenticatorTester.java b/component/security/shiro/src/test/java/org/apache/isis/security/shiro/ShiroAuthenticatorTester.java
new file mode 100644
index 0000000..f7fade1
--- /dev/null
+++ b/component/security/shiro/src/test/java/org/apache/isis/security/shiro/ShiroAuthenticatorTester.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.security.shiro;
+
+import org.apache.isis.core.commons.config.IsisConfiguration;
+import org.apache.isis.core.runtime.authentication.AuthenticationRequestPassword;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.core.unittestsupport.jmock.auto.Mock;
+import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2;
+import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2.Mode;
+import org.apache.isis.security.shiro.ShiroAuthenticatorOrAuthorizor;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.IncorrectCredentialsException;
+import org.apache.shiro.authc.LockedAccountException;
+import org.apache.shiro.authc.UnknownAccountException;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.config.IniSecurityManagerFactory;
+import org.apache.shiro.mgt.SecurityManager;
+import org.apache.shiro.session.Session;
+import org.apache.shiro.subject.Subject;
+import org.apache.shiro.util.Factory;
+import org.jmock.Expectations;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class ShiroAuthenticatorTester {
+
+ @Rule
+ public JUnitRuleMockery2 context = JUnitRuleMockery2.createFor(Mode.INTERFACES_AND_CLASSES);
+
+ @Mock
+ private IsisConfiguration mockConfiguration;
+
+ private ShiroAuthenticatorOrAuthorizor authenticator;
+
+ @Before
+ public void setUp() throws Exception {
+ authenticator = new ShiroAuthenticatorOrAuthorizor(mockConfiguration);
+ }
+
+ @Test
+ public void xxx() throws Exception {
+
+ context.checking(new Expectations() {
+ {
+ allowing(mockConfiguration).getString("isis.authentication.shiro.iniClasspath");
+ will(returnValue("classpath:shiro.ini"));
+ }
+ });
+
+
+ // Use the shiro.ini file at the root of the classpath
+ // (file: and url: prefixes load from files and urls respectively):
+ Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
+ SecurityManager securityManager = factory.getInstance();
+
+ // for this simple example quickstart, make the SecurityManager
+ // accessible as a JVM singleton. Most applications wouldn't do this
+ // and instead rely on their container configuration or web.xml for
+ // webapps. That is outside the scope of this simple quickstart, so
+ // we'll just do the bare minimum so you can continue to get a feel
+ // for things.
+ SecurityUtils.setSecurityManager(securityManager);
+
+ // Now that a simple Shiro environment is set up, let's see what you can do:
+
+ // get the currently executing user:
+ Subject currentUser = SecurityUtils.getSubject();
+
+ // Do some stuff with a Session (no need for a web or EJB container!!!)
+ Session session = currentUser.getSession();
+ session.setAttribute("someKey", "aValue");
+ String value = (String) session.getAttribute("someKey");
+ if (value.equals("aValue")) {
+ System.out.println("Retrieved the correct value! [" + value + "]");
+ }
+
+ // let's login the current user so we can check against roles and permissions:
+ if (!currentUser.isAuthenticated()) {
+ UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
+ token.setRememberMe(true);
+ try {
+ currentUser.login(token);
+ } catch (UnknownAccountException uae) {
+ System.out.println("There is no user with username of " + token.getPrincipal());
+ } catch (IncorrectCredentialsException ice) {
+ System.out.println("Password for account " + token.getPrincipal() + " was incorrect!");
+ } catch (LockedAccountException lae) {
+ System.out.println("The account for username " + token.getPrincipal() + " is locked. " +
+ "Please contact your administrator to unlock it.");
+ }
+ // ... catch more exceptions here (maybe custom ones specific to your application?
+ catch (AuthenticationException ae) {
+ //unexpected condition? error?
+ }
+ }
+
+ //say who they are:
+ //print their identifying principal (in this case, a username):
+ System.out.println("User [" + currentUser.getPrincipal() + "] logged in successfully.");
+
+ //test a role:
+ if (currentUser.hasRole("schwartz")) {
+ System.out.println("May the Schwartz be with you!");
+ } else {
+ System.out.println("Hello, mere mortal.");
+ }
+
+ //test a typed permission (not instance-level)
+ if (currentUser.isPermitted("lightsaber:weild")) {
+ System.out.println("You may use a lightsaber ring. Use it wisely.");
+ } else {
+ System.out.println("Sorry, lightsaber rings are for schwartz masters only.");
+ }
+
+ //a (very powerful) Instance Level permission:
+ if (currentUser.isPermitted("winnebago:drive:eagle5")) {
+ System.out.println("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'. " +
+ "Here are the keys - have fun!");
+ } else {
+ System.out.println("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
+ }
+
+ //all done - log out!
+ currentUser.logout();
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/95c0b553/component/security/shiro/src/test/java/org/apache/isis/security/shiro/authorization/ShiroAuthorizorTester.java
----------------------------------------------------------------------
diff --git a/component/security/shiro/src/test/java/org/apache/isis/security/shiro/authorization/ShiroAuthorizorTester.java b/component/security/shiro/src/test/java/org/apache/isis/security/shiro/authorization/ShiroAuthorizorTester.java
new file mode 100644
index 0000000..b1fc4dc
--- /dev/null
+++ b/component/security/shiro/src/test/java/org/apache/isis/security/shiro/authorization/ShiroAuthorizorTester.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.isis.security.shiro.authorization;
+
+import org.apache.isis.core.commons.config.IsisConfiguration;
+import org.apache.isis.core.runtime.authentication.AuthenticationRequestPassword;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.core.unittestsupport.jmock.auto.Mock;
+import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2;
+import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2.Mode;
+import org.apache.isis.security.shiro.ShiroAuthenticatorOrAuthorizor;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.IncorrectCredentialsException;
+import org.apache.shiro.authc.LockedAccountException;
+import org.apache.shiro.authc.UnknownAccountException;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.config.IniSecurityManagerFactory;
+import org.apache.shiro.mgt.SecurityManager;
+import org.apache.shiro.session.Session;
+import org.apache.shiro.subject.Subject;
+import org.apache.shiro.util.Factory;
+import org.jmock.Expectations;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class ShiroAuthorizorTester {
+
+ @Rule
+ public JUnitRuleMockery2 context = JUnitRuleMockery2.createFor(Mode.INTERFACES_AND_CLASSES);
+
+ @Mock
+ private IsisConfiguration mockConfiguration;
+
+ private ShiroAuthenticatorOrAuthorizor authenticator;
+
+ @Before
+ public void setUp() throws Exception {
+ authenticator = new ShiroAuthenticatorOrAuthorizor(mockConfiguration);
+ }
+
+ @Test
+ public void xxx() throws Exception {
+
+ context.checking(new Expectations() {
+ {
+ allowing(mockConfiguration).getString("isis.authentication.shiro.iniClasspath");
+ will(returnValue("classpath:shiro.ini"));
+ }
+ });
+
+
+ // Use the shiro.ini file at the root of the classpath
+ // (file: and url: prefixes load from files and urls respectively):
+ Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
+ SecurityManager securityManager = factory.getInstance();
+
+ // for this simple example quickstart, make the SecurityManager
+ // accessible as a JVM singleton. Most applications wouldn't do this
+ // and instead rely on their container configuration or web.xml for
+ // webapps. That is outside the scope of this simple quickstart, so
+ // we'll just do the bare minimum so you can continue to get a feel
+ // for things.
+ SecurityUtils.setSecurityManager(securityManager);
+
+
+ // Now that a simple Shiro environment is set up, let's see what you can do:
+
+ // get the currently executing user:
+ Subject currentUser = SecurityUtils.getSubject();
+
+ // Do some stuff with a Session (no need for a web or EJB container!!!)
+ Session session = currentUser.getSession();
+ session.setAttribute("someKey", "aValue");
+ String value = (String) session.getAttribute("someKey");
+ if (value.equals("aValue")) {
+ System.out.println("Retrieved the correct value! [" + value + "]");
+ }
+
+ // let's login the current user so we can check against roles and permissions:
+ if (!currentUser.isAuthenticated()) {
+ UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
+ token.setRememberMe(true);
+ try {
+ currentUser.login(token);
+ } catch (UnknownAccountException uae) {
+ System.out.println("There is no user with username of " + token.getPrincipal());
+ } catch (IncorrectCredentialsException ice) {
+ System.out.println("Password for account " + token.getPrincipal() + " was incorrect!");
+ } catch (LockedAccountException lae) {
+ System.out.println("The account for username " + token.getPrincipal() + " is locked. " +
+ "Please contact your administrator to unlock it.");
+ }
+ // ... catch more exceptions here (maybe custom ones specific to your application?
+ catch (AuthenticationException ae) {
+ //unexpected condition? error?
+ }
+ }
+
+ //say who they are:
+ //print their identifying principal (in this case, a username):
+ System.out.println("User [" + currentUser.getPrincipal() + "] logged in successfully.");
+
+ //test a role:
+ if (currentUser.hasRole("schwartz")) {
+ System.out.println("May the Schwartz be with you!");
+ } else {
+ System.out.println("Hello, mere mortal.");
+ }
+
+ //test a typed permission (not instance-level)
+ if (currentUser.isPermitted("lightsaber:weild")) {
+ System.out.println("You may use a lightsaber ring. Use it wisely.");
+ } else {
+ System.out.println("Sorry, lightsaber rings are for schwartz masters only.");
+ }
+
+ //a (very powerful) Instance Level permission:
+ if (currentUser.isPermitted("winnebago:drive:eagle5")) {
+ System.out.println("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'. " +
+ "Here are the keys - have fun!");
+ } else {
+ System.out.println("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
+ }
+
+ //all done - log out!
+ currentUser.logout();
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/95c0b553/component/security/shiro/src/test/resources/shiro.ini
----------------------------------------------------------------------
diff --git a/component/security/shiro/src/test/resources/shiro.ini b/component/security/shiro/src/test/resources/shiro.ini
new file mode 100644
index 0000000..adca38c
--- /dev/null
+++ b/component/security/shiro/src/test/resources/shiro.ini
@@ -0,0 +1,58 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# =============================================================================
+# Quickstart INI Realm configuration
+#
+# For those that might not understand the references in this file, the
+# definitions are all based on the classic Mel Brooks' film "Spaceballs". ;)
+# =============================================================================
+
+# -----------------------------------------------------------------------------
+# Users and their assigned roles
+#
+# Each line conforms to the format defined in the
+# org.apache.shiro.realm.text.TextConfigurationRealm#setUserDefinitions JavaDoc
+# -----------------------------------------------------------------------------
+[users]
+# user 'root' with password 'secret' and the 'admin' role
+root = secret, admin
+# user 'guest' with the password 'guest' and the 'guest' role
+guest = guest, guest
+# user 'presidentskroob' with password '12345' ("That's the same combination on
+# my luggage!!!" ;)), and role 'president'
+presidentskroob = 12345, president
+# user 'darkhelmet' with password 'ludicrousspeed' and roles 'darklord' and 'schwartz'
+darkhelmet = ludicrousspeed, darklord, schwartz
+# user 'lonestarr' with password 'vespa' and roles 'goodguy' and 'schwartz'
+lonestarr = vespa, goodguy, schwartz
+
+# -----------------------------------------------------------------------------
+# Roles with assigned permissions
+#
+# Each line conforms to the format defined in the
+# org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc
+# -----------------------------------------------------------------------------
+[roles]
+# 'admin' role has all permissions, indicated by the wildcard '*'
+admin = *
+# The 'schwartz' role can do anything (*) with any lightsaber:
+schwartz = lightsaber:*
+# The 'goodguy' role is allowed to 'drive' (action) the winnebago (type) with
+# license plate 'eagle5' (instance specific id)
+goodguy = winnebago:drive:eagle5