Setting up

This section describes how to setup and configure SecMan for use in your Apache Isis application.

Dependency Management

If your application inherits from the Apache Isis starter app (org.apache.isis.app:isis-app-starter-parent) then that will define the version automatically:

pom.xml
<parent>
    <groupId>org.apache.isis.app</groupId>
    <artifactId>isis-app-starter-parent</artifactId>
    <version>2.0.0-M6</version>
    <relativePath/>
</parent>

Alternatively, import the core BOM. This is usually done in the top-level parent pom of your application:

pom.xml
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.apache.isis.core</groupId>
            <artifactId>isis-core</artifactId>
            <version>2.0.0-M6</version>
            <scope>import</scope>
            <type>pom</type>
        </dependency>
    </dependencies>
</dependencyManagement>

In addition, add a section for secman’s own BOM:

pom.xml
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.apache.isis.extensions</groupId>
            <artifactId>isis-extensions-secman</artifactId>
            <scope>import</scope>
            <type>pom</type>
            <version>2.0.0-M6</version>
        </dependency>
    </dependencies>
</dependencyManagement>

Dependencies

In the webapp module of your application, add the following dependency:

pom.xml
<dependencies>
        <dependency>
            <groupId>org.apache.isis.extensions</groupId>
            <artifactId>isis-extensions-secman-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.isis.extensions</groupId>
            <artifactId>isis-extensions-secman-model</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.isis.extensions</groupId>
            <artifactId>isis-extensions-secman-persistence-XXX</artifactId> (1)
        </dependency>
        <dependency>
            <groupId>org.apache.isis.extensions</groupId>
            <artifactId>isis-extensions-secman-encryption-jbcrypt</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.isis.extensions</groupId>
            <artifactId>isis-extensions-secman-shiro-realm</artifactId>
        </dependency>
</dependencies>
1 specify either isis-extensions-secman-persistence-jpa or isis-extensions-secman-persistence-jdo, as required

Update AppManifest

Import modules

In your application’s AppManifest (top-level Spring @Configuration used to bootstrap the app), import the SecMan modules. You will also need to import the fixture module; SecMan uses fixture scripts to seed its entities:

AppManifest.java
@Configuration
@Import({
        ...
        IsisModuleSecurityShiro.class,                  (1)
        ...
        IsisModuleExtSecmanApi.class,                   (2)
        IsisModuleExtSecmanModel.class,
        IsisModuleExtSecmanPersistenceJpa.class,
        IsisModuleExtSecmanRealmShiro.class,
        IsisModuleExtSecmanEncryptionJbcrypt.class,

        IsisModuleTestingFixturesApplib.class,          (3)
        ...
})
public class AppManifest {
}
1 enable Shiro for security.

Ensure that no other IsisModuleSecurityXxx module is imported.

2 SecMan dependencies
3 fixture script support

Configure Services

It is also necessary to configure some aspects of SecMan. This is most easily done using Bean definitions within the AppManifest:

AppManifest.java
//...
public class AppManifest {

    @Bean
    public SecmanConfiguration secmanConfiguration() {
        return SecmanConfiguration.builder()
                .adminUserName("sven").adminPassword("pass")      (1)
                .adminRoleName("isis-ext-secman-admin-role")      (2)
                .regularUserRoleName("isis-ext-secman-user-role") (3)
                .build();
    }

    @Bean
    public PermissionsEvaluationService permissionsEvaluationService() {
        return new PermissionsEvaluationServiceAllowBeatsVeto();    (4)
    }

    @Bean
    public SecurityRealmService securityRealmService() {
        return new SecurityRealmService() {
            @Override
            public SecurityRealm getCurrentRealm() {
                return () ->
                    EnumSet.noneOf(SecurityRealmCharacteristic.class); (5)
            }
        };
    }
}
1 indicates the security super-user and password
2 indicates the name of the role granted to this security super-user. This can be any name.
3 indicates the name of the role that should be granted to regular users of the application.
This role grants regular users the ability to logout (among other things).
4 indicates that only local users are supported (no delegate realm is in used).

See below to configure for a delegate realm.

Shiro Realm

SecMan’s Shiro realm is configured using the shiro.ini file:

shiro.ini
[main]

authenticationStrategy=org.apache.isis.extensions.secman.shiro.AuthenticationStrategyForIsisModuleSecurityRealm
isisModuleSecurityRealm=org.apache.isis.extensions.secman.shiro.IsisModuleExtSecmanShiroRealm

securityManager.authenticator.authenticationStrategy = $authenticationStrategy
securityManager.realms = $isisModuleSecurityRealm

[users]
[roles]

The [users] and [roles] sections are required but are unused.

Delegate Realms

If a delegate realm is to be used, then there are two changes required.

  • first, in the AppManifest:

    AppManifest.java
    @Bean
    public SecurityRealmService securityRealmService() {
        return new SecurityRealmService() {
            @Override
            public SecurityRealm getCurrentRealm() {
                return () -> EnumSet.of(SecurityRealmCharacteristic.DELEGATING);
            }
        };
    }
  • second, specify the delegate realm implementation in the shiro.ini file, and "inject" it into the semcan realm.

    For example, to use LDAP Realm for Shiro as a delegate:

    shiro.ini
    [main]
    
    ...
    ldapRealm=org.apache.isis.extensions.shirorealmldap.realm.impl.IsisLdapRealm (1)
    ldapRealm.xxx=...                                                            (2)
    ldapRealm.yyy=...
    
    isisModuleSecurityRealm.delegateAuthenticationRealm=$ldapRealm               (3)
    
    ...
    1 instantiate the LDAP realm
    2 configure the LDAP realm as required
    3 specify the LDAP realm as the delegate realm for SecMan’s own realm.

Seed Users and Roles

With SecMan enabled, it will automatically set up a security super-user (as described above) and a regular role.

Creating regular applications users thereafter can be done manually, but if prototyping with an in-memory database then you will most likely want to set up some fixure scripts to automatically set up application users.

SecMan provides a number of convenience fixture scripts to inherit from. For example, these scripts can be used to set up access to the domain objects in the HelloWorld starter app:

  • to set up a "user-rw" role with access to everything under the "hello" namespace:

    RoleAndPerms__UserRw.java
    public class RoleAndPerms__UserRw extends AbstractRoleAndPermissionsFixtureScript {
    
        public static final String ROLE_NAME = "user-rw";
    
        public RoleAndPerms__UserRw() {
            super(ROLE_NAME, "Read-write access to entire application");
        }
    
        @Override
        protected void execute(ExecutionContext ec) {
            newPermissions(
                    ApplicationPermissionRule.ALLOW,
                    ApplicationPermissionMode.CHANGING,
                    Can.of(ApplicationFeatureId.newNamespace("hello"))
            );
        }
    }
  • to set up a "no-delete" role that vetoes the ability to delete objects:

    RoleAndPerms__UserRw.java
    public class RoleAndPerms__NoDelete extends AbstractRoleAndPermissionsFixtureScript {
    
        public static final String ROLE_NAME = "no-delete";
    
        public RoleAndPerms__NoDelete() {
            super(ROLE_NAME, "Veto access to deleting HelloWorld objects");
        }
    
        @Override
        protected void execute(ExecutionContext ec) {
            newPermissions(
                    ApplicationPermissionRule.VETO,
                    ApplicationPermissionMode.VIEWING,
                    Can.of(ApplicationFeatureId.newFeature(ApplicationFeatureSort.MEMBER, "hello.HelloWorldObject#delete"))
            );
        }
    }
  • to set up a user "joe" with the "user-rw" and "no-delete" role:

    UserToRole__bob_UserRw.java
    public class UserToRole__bob_UserRw extends AbstractUserAndRolesFixtureScript {
    
        public UserToRole__bob_UserRw() {
            super("joe", "pass", "bob@world.com",
                    "/ITA",
                    AccountType.LOCAL,
                    Can.of(
                       RoleAndPerms__UserRw.ROLE_NAME,
                       RoleAndPerms__NoDelete.ROLE_NAME
                    ));
        }
    }