= Setting up

:Notice: 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.
:page-partial:

This section describes how to setup and configure SecMan for use in your Apache Isis application, for both authentication (`Authenticator` SPI) and authorization (`Authorizor` SPI).

It is also possible to use SecMan in conjunction with the framework's xref:security:shiro:about.adoc[integration with Shiro], where Shiro takes primary responsibility for authentication, while still using Secman for authorization.
This mode allows a separate authentication mechanism such as LDAP to be used.
For more details, see xref:setting-up-with-shiro.adoc[setting up with Shiro].



include::docs:mavendeps:partial$setup-and-configure-dependencyManagement.adoc[leveloffset=+1]

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

[source,xml,subs="attributes+"]
.pom.xml
----
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.apache.isis.extensions</groupId>
            <artifactId>isis-extensions-secman</artifactId>
            <scope>import</scope>
            <type>pom</type>
            <version>{page-isisrel}</version>
        </dependency>
    </dependencies>
</dependencyManagement>
----

[#dependencies]
== Dependencies

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

[source,xml]
.pom.xml
----
<dependencies>
    <dependency>
        <groupId>org.apache.isis.extensions</groupId>
        <artifactId>isis-extensions-secman-persistence-XXX</artifactId>    <!--.-->
    </dependency>
    <dependency>
        <groupId>org.apache.isis.extensions</groupId>
        <artifactId>isis-extensions-secman-encryption-jbcrypt</artifactId> <!--.-->
    </dependency>
</dependencies>
----
<.> specify either `isis-extensions-secman-persistence-jpa` or `isis-extensions-secman-persistence-jdo`, as required
<.> provides an implementation of `PasswordEncoder`, so that passwords are only persisted in encrypted form.


[[_update-appmanifest]]
== Update AppManifest


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:

[source,java]
.AppManifest.java
----
@Configuration
@Import({
        ...
        IsisModuleExtSecmanPersistenceXxx.class,        // <.>
        IsisModuleExtSecmanEncryptionJbcrypt.class,     // <.>

        IsisModuleTestingFixturesApplib.class,          // <.>
        ...
})
public class AppManifest {
}
----

<.> specify either `IsisModuleExtSecmanPersistenceJdo` or `IsisModuleExtSecmanPersistenceJpa`, as required
<.> use Jbcrypt to encrypt passwords
<.> fixture script support

In addition, you will probably want to *remove* the `IsisModuleSecurityShiro.class` dependency so that SecMan can take care of both authentication _and_ authorisation.

[NOTE]
====
It also possible to use SecMan in conjunction with Shiro, as described xref:setting-up-with-shiro.adoc[here].
The primary use case is to support delegated users that Shiro authenticates externally using LDAP, for example.
====

[#configure-properties]
== Configuration Properties

Add the database schema used by the SecMan entities to the configuration file:

[source,yaml]
.application.yml
----
isis:
  persistence:
    schema:
      auto-create-schemas: isisExtSecman
----

Optionally, modify the configuration properties for Secman itself:

[source,yaml]
.application.yml
----
isis:
  extensions:
    secman:
      seed:
        admin:
          user-name: "secman-admin"                     #<.>
          password: "pass"                              #<1>
          role-name: "isis-ext-secman-admin"            #<.>
          namespace-permissions:
            sticky: ...                                 #<.>
            additional: ...                             #<.>
        regular-user:
          role-name: "isis-ext-secman-user"             #<.>
      permissions-evaluation-policy: allow_beats_veto   #<.>
      user-menu-me-action-policy: hide                  #<.>
      user-registration:
        initial-role-names: ...                         #<.>

----

<.> indicates the security super-user and password
<.> indicates the name of the role granted to this security super-user.
This can be any name.
<.> the "sticky" namespace permissions granted to the admin role.
These cannot be removed (through the UI).
<.> any additional namespace permissions to be granted to the admin role.
These can be removed (through the UI).
<.> indicates the name of the role that should be granted to regular users of the application.
<.> if there are conflicted (allow vs veto) permissions at the same scope, then whether the allow wins or the veto wins
<.> whether to HIDE, DISABLE or ENABLE the default "me" action provided by the core framework.
Normally this should be hidden, because secman's `ApplicationUser` broadly replaces the core framework's `UserMemento`.
<.> if self-user registration is enabled in the viewer, this defines the set of roles to be granted to said user.
+
This is discussed in more detail <<user-registration-aka-sign-up,below>>.


== menubar.layout.xml

SecMan provides a large number of menu actions.
You can use `menubars.layout.xml` to arrange these as you see fit.
To get you started, the following fragment adds all of the actions to a "Security" secondary menu:

[source,xml]
.menubars.layout.xml
----
<mb3:secondary>
    ...
    <mb3:menu>
        <mb3:named>Security</mb3:named>
        <mb3:section>
            <mb3:named>Users</mb3:named>
            <mb3:serviceAction objectType="isis.ext.secman.ApplicationUserMenu" id="userManager"/>
            <mb3:serviceAction objectType="isis.ext.secman.ApplicationUserMenu" id="findUsers"/>
        </mb3:section>
        <mb3:section>
            <mb3:named>Roles</mb3:named>
            <mb3:serviceAction objectType="isis.ext.secman.ApplicationRoleMenu" id="findRoles"/>
            <mb3:serviceAction objectType="isis.ext.secman.ApplicationRoleMenu" id="newRole"/>
            <mb3:serviceAction objectType="isis.ext.secman.ApplicationRoleMenu" id="allRoles"/>
        </mb3:section>
        <mb3:section>
            <mb3:named>Permissions</mb3:named>
            <mb3:serviceAction objectType="isis.ext.secman.ApplicationPermissionMenu" id="allPermissions"/>
            <mb3:serviceAction objectType="isis.ext.secman.ApplicationPermissionMenu" id="findOrphanedPermissions"/>
        </mb3:section>
        <mb3:section>
            <mb3:named>Tenancies</mb3:named>
            <mb3:serviceAction objectType="isis.ext.secman.ApplicationTenancyMenu" id="findTenancies"/>
            <mb3:serviceAction objectType="isis.ext.secman.ApplicationTenancyMenu" id="newTenancy"/>
            <mb3:serviceAction objectType="isis.ext.secman.ApplicationTenancyMenu" id="allTenancies"/>
        </mb3:section>
    </mb3:menu>
</mb3:secondary>
----

We also recommend adding the non-production "me" action to the tertiary menu, eg just above the "logout" action:

[source,xml]
.menubars.layout.xml
----
<mb3:tertiary>
    <mb3:menu>
        ...
        <mb3:section>
            <mb3:serviceAction objectType="isis.ext.secman.MeService" id="me"/>
            <mb3:serviceAction objectType="isis.security.LogoutMenu" id="logout"/>
        </mb3:section>
    </mb3:menu>
</mb3:tertiary>
----



[#default-roles]
== Default Roles

With SecMan enabled, it will automatically seed a security super-user and a regular role.
It also creates a number of other roles to provide access to specific features of the framework (or its extensions).
This seeding is performed by the  xref:refguide:extensions:index/secman/applib/seed/SeedSecurityModuleService.adoc[SeedSecurityModuleService], which calls xref:refguide:extensions:index/secman/applib/seed/scripts/SeedUsersAndRolesFixtureScript.adoc[SeedUsersAndRolesFixtureScript].

The full list of roles set up is summarised here:

* Available in both production and prototype mode

** Admin role (as defined in the configuration, see <<configure-properties,above>>)
+
Admin permissions for Secman itself.
This is the role granted to the security super-user, and whose exact name is configured using .
This role should therefore be extremely tightly locked down.

** Regular user role (as defined in the configuration, see <<configure-properties,above>>)
+
Regular user permissions for Secman.
This should be granted to all users (in particular, it includes the ability to logout!)

** `IsisConfigurationRoleAndPermissions.ROLE_NAME`
+
Access the configuration properties (from the tertiary menu))

* Available only in prototype mode:

** `IsisAppFeatureRoleAndPermissions.ROLE_NAME`
+
Browse the application features + permissions (from the "Prototyping" menu).

** `IsisPersistenceJdoMetaModelRoleAndPermissions.ROLE_NAME`
+
Download the JDO metamodel (from the "Prototyping" menu).

// moved to the incubator for the time being
//** `IsisExtCommandReplayPrimaryRoleAndPermissions.ROLE_NAME`
//+
//Access to the command replay primary menu
//
//** `IsisExtCommandReplaySecondaryRoleAndPermissions.ROLE_NAME`
//+
//Access to the command replay secondary menu
//

** `IsisExtH2ConsoleRoleAndPermissions.ROLE_NAME`
+
Access the h2 console (from the "Prototyping" menu)

** `IsisViewerRestfulObjectsSwaggerRoleAndPermissions.ROLE_NAME`
+
Access the swagger UI (from the "Prototyping" menu)

** `IsisSudoImpersonateRoleAndPermissions.ROLE_NAME`
+
Impersonate other users (from the "Prototyping" menu, and mixins)

The full list can be found by searching for subclasses of xref:refguide:extensions:index/secman/applib/role/fixtures/ AbstractRoleAndPermissionsFixtureScript.adoc[AbstractRoleAndPermissionsFixtureScript].

[NOTE]
====
There is no fixture script to setup a role to access the UI features of the applib, or to run fixture scripts; these are included automatically as part of the SecMan's own "regular user".
====



== Fixture scripts and seed service, to setup users and roles

If prototyping with an in-memory database then you will most likely want to set up some fixture scripts to automatically set up application users.

As noted <<default-roles, above>>, SecMan automatically seeds the built-in roles and users, so it is only necessary to set up roles and users specific to the application.

To save some boilerplate, you can subclass:

* xref:refguide:extensions:index/secman/applib/role/fixtures/AbstractRoleAndPermissionsFixtureScript.adoc[AbstractRoleAndPermissionsFixtureScript]
+
to create a role and associated permissions

* xref:refguide:extensions:index/secman/applib/user/fixtures/AbstractUserAndRolesFixtureScript.adoc[AbstractUserAndRolesFixtureScript]
+
to create a user and associated roles.

You then will need a way to automatically ensure these users/roles are set up on bootstrapping; this is discussed next.

[#custom-seed-service]
=== Custom Seed Service

When developing the app you will probably be using the H2 in-memory database, and so you'll want to ensure that the roles and (perhaps) users are automatically seeded into the database.
Even when running in production with a persistent database, running a default set of fixture scripts may be worthwihle.

One option to setup these users/roles would be to use the xref:refguide:config:sections/isis.testing.adoc#isis.testing.fixtures.initial-script[isis.testing.fixtures.initial-script] configuration property.
However the purpose of that config property is meant to be to setup an application-specific scenario for demoing/prototyping, so that's probably not the smartest approach.

A better approach is to write a little domain service to do the seeding of security data for you.
The service below will set up the default roles and permissions for the framework's own modules:

[source,java]
.SeedUsersAndRoles.java
----
@Service
@Priority(PriorityPrecedence.MIDPOINT + 10)
@RequiredArgsConstructor(onConstructor_ = {@Inject})
public class SeedSecurityService {

    private final FixtureScripts fixtureScripts;
    private final TransactionService transactionService;
    private final IsisSystemEnvironment isisSystemEnvironment;

    @EventListener(MetamodelEvent.class)
    public void onMetamodelEvent(final MetamodelEvent event) {
        if (event.isPostMetamodel() && isisSystemEnvironment.isPrototyping()) {
            runScripts();
            transactionService.flushTransaction();
        }
    }

    private void runScripts() {
        fixtureScripts.run(new CustomRolesAndUsers());
}
----

where `CustomRolesAndUsers` is a top-level fixture script to set up the application-specific users and roles.

=== Examples

For example, the following scripts could be used to set up access to the domain objects in the xref:docs:starters:helloworld.adoc[HelloWorld] starter app:

* to set up a "user-rw" role with access to everything under the "hello" namespace:
+
[source,java]
.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 user bob with access to this role plus all available <<default-roles, built-in roles>>:
+
[source,java]
.UserToRole__bob_allRoles.java
----
public class UserToRole__bob_allRoles extends AbstractUserAndRolesFixtureScript {

  public UserToRole__bob_allRoles() {
    super(
      "bob", "pass",          // <.>
      "bob@cratchet.com",     // <.>
      "/",                    // <.>
      AccountType.LOCAL,      // <.>
      Can.of(
        RoleAndPerms__UserRw.ROLE_NAME                                            // <.>
        , IsisConfiguration.Extensions.Secman.Seed.REGULAR_USER_ROLE_NAME_DEFAULT // <.>
        , IsisAppFeatureRoleAndPermissions.ROLE_NAME                   // <.>
        , IsisPersistenceJdoMetaModelRoleAndPermissions.ROLE_NAME      // <7>
        , IsisExtCommandReplayPrimaryRoleAndPermissions.ROLE_NAME      // <7>
        , IsisExtCommandReplaySecondaryRoleAndPermissions.ROLE_NAME    // <7>
        , IsisExtH2ConsoleRoleAndPermissions.ROLE_NAME                 // <7>
        , IsisViewerRestfulObjectsSwaggerRoleAndPermissions.ROLE_NAME  // <7>
        , IsisSudoImpersonateRoleAndPermissions.ROLE_NAME              // <7>
        , IsisConfigurationRoleAndPermissions.ROLE_NAME                // <7>
      ));
  }
}
----

<.> username and password.
The password is encrypted, not stored in plain text.
<.> email address
<.> application tenancy
<.> local account (rather than delegated, see xref:setting-up-with-shiro.adoc[])
<.> application-specific roles
<.> regular user access (always required).
*Note* that this expects that the default regular user role has been left as its default value.
<.> specific access to framework features, see <<default-roles,above>>


We can also veto individual members:

* to set up a "no-delete" role that vetoes the ability to delete objects:
+
[source,java]
.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:
+
[source,java]
.UserToRole__joe_UserRw_but_NoDelete.java
----
public class UserToRole__joe_UserRw_but_NoDelete
    extends AbstractUserAndRolesFixtureScript {

  public UserToRole__joe_UserRw_but_NoDelete() {
    super(
      "joe", "pass",
      "joe@italy.com",
      "/ITA",
      AccountType.LOCAL,
      Can.of(
        RoleAndPerms__UserRw.ROLE_NAME                                           // <.>
        ,RoleAndPerms__NoDelete.ROLE_NAME                                        // <1>
        ,IsisConfiguration.Extensions.Secman.Seed.REGULAR_USER_ROLE_NAME_DEFAULT // <.>
    ));
  }
}
----
<.> application-specific roles
<.> regular user access (always required)

To seed in fixture scripts we could create a top-level `CustomRolesAndUsers` script (as mentioned in <<custom-seed-service,above>>).
This would then look something like:

[source,java]
.CustomRolesAndUsers.java
----
public class CustomRolesAndUsers extends FixtureScript {

    @Override protected void execute(ExecutionContext executionContext) {
        executionContext.executeChildren(this,
                // roles
                new RoleAndPerms__HelloRw()
                // users
                , new UserToRole__bob_allRoles()
                , new UserToRole__joe_UserRw_but_NoDelete()
        );
    }
}
----

The custom seed service would then ensure that these users/roles existed on startup.


== Creating Users and Roles

Once a super-user admin account has been seeded in, regular users can be created manually by logging in as that security super-user.

Alternatively, users can be created programmatically through xref:refguide:extensions:index/secman/applib/user/dom/ApplicationUserRepository.adoc[ApplicationUserRepository].
This will return an xref:refguide:extensions:index/secman/applib/user/dom/ApplicationUser.adoc[ApplicationUser] which can then be granted roles, for example using `addRoleToUser()` API of xref:refguide:extensions:index/secman/applib/role/dom/ApplicationRoleRepository.adoc[ApplicationRoleRepository].


[#user-registration-aka-sign-up]
== User registration (aka Sign-up)

Secman provides an implementation of the xref:refguide:applib:index/services/userreg/UserRegistrationService.adoc[UserRegistrationService] SPI.
This means, if the viewer supports it (eg the Wicket viewer's xref:vw::features/user-registration.adoc[sign-up support]), then end-users can sign-up to create an account via email.
The Secman implementation sets up the user with appropriate initial roles.

The exact roles to setup are specified using configuration property:

[source,yaml]
.application.yaml
----
isis:
  extensions:
    secman:
      user-registration:
        initial-roles:
          - "self-registered-user-role"
          - "regular-user-role"
----

