<commit_before>= Configuring Shiro
: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.
:_basedir: ../
:_imagesdir: images/


Apache Isis' security mechanism is configurable, specifying an `Authenticator` and an `Authorizor` (non-public) APIs.  The Shiro security mechanism is an integration wih Apache Shiro that implements both interfaces.

[TIP]
====
The <<_simpleapp_archetype, SimpleApp archetype>> is pre-configured to use Apache Shiro, so much of what follows is set up already.
====

== Specifying Shiro as the security mechanism

To tell Apache Isis to use Shiro, update the `WEB-INF/isis.properties` file:

[source,ini]
----
isis.authentication=shiro
isis.authorization=shiro
----

This installs the appropriate implementation (the `ShiroAuthenticatorOrAuthorizor` class) that use Shiro's APIs to perform authentication and authorization.




== Bootstrapping Shiro

The Shiro environment (in essence, thread-locals holding the security credentials) needs to be bootstrapped using the following settings in the `WEB-INF/web.xml` file:

[source,xml]
----
<listener>
    <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>

<filter>
    <filter-name>ShiroFilter</filter-name>
    <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>ShiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
----

Based on this Shiro will then read `WEB-INF/shiro.ini` file to configure its Realm definitions for authentication and authorization.




== `WEB-INF/shiro.ini`

The `shiro.ini` file (at least as configured in the <<_simpleapp_archetype, SimpleApp archetype>>) is configured to use the built-in `$iniRealm`.  This is achieved by the line:

[source,ini]
----
securityManager.realms = $iniRealm
----

The file also (by way of example) include entries to setup an ldapRealm, but this is not wired in. For more information on LDAP, see link:./using-ldap.html[here].

Specifying `$iniRealm` means that the usernames/passwords, roles and permissions are read from the `shiro.ini` file itself.

* the users/passwords and their roles from the `[users]` sections;
* the roles are mapped to permissions in the `[roles]` section.


=== Users section

The `[users]` section lists users, passwords and their roles. For example:

[source,ini]
----
sven = pass, admin_role
dick = pass, user_role, analysis_role, self-install_role
bob  = pass, user_role, self-install_role
----

=== Roles section

The `roles` section lists roles and their corresponding permissions. For example:

[source,ini]
----
user_role = *:ToDoItems:*:*,\
            *:ToDoItem:*:*,\
            *:ToDoAppDashboard:*:*
analysis_role = *:ToDoItemAnalysis:*:*,\
            *:ToDoItemsByCategoryViewModel:*:*,\
            *:ToDoItemsByDateRangeViewModel:*:*
self-install_role = *:ToDoItemsFixturesService:install:*
admin_role = *
----

=== Permissions format

The permission format is configurable. The default format is:

[source,ini]
----
packageName:className:memberName:r,w
----

where:

* `memberName` is the property, collection or action name.
* `r` indicates that the member is visible
* `w` indicates that the member is usable (editable or invokable)

and where each of the parts of the permission string can be wildcarded using `*`.

Because these are wildcards, a '*' can be used at any level. Additionally, missing levels assume wildcards.  Thus:

[source]
----
com.mycompany.myapp:Customer:firstName:r,w   # view or edit customer's firstName
com.mycompany.myapp:Customer:lastName:r      # view customer's lastName only
com.mycompany.myapp:Customer:placeOrder:*    # view and invoke placeOrder action
com.mycompany.myapp:Customer:placeOrder      # ditto
com.mycompany.myapp:Customer:*:r             # view all customer class members
com.mycompany.myapp:*:*:r                    # view-only access for all classes in myapp package
com.mycompany.myapp:*:*:*                    # view/edit for all classes in myapp package
com.mycompany.myapp:*:*                      # ditto
com.mycompany.myapp:*                        # ditto
com.mycompany.myapp                          # ditto
*                                            # view/edit access to everything
----




==== Using the Enhanced Isis Permission Syntax

Shiro also allows the conversion to be mapped to alternative `Permission` instances; Isis provides its own `IsisPermission` which provides an extended and more flexible syntax.


Isis defines its own extended syntax for permissions, following the format:

[source,ini]
----
([!]?)([^/]+)[/](.+)
----

where:

* the optional `!` prefix indicates this permission is a vetoing permission
* the optional `xxx/` prefix is a permission group that scopes any vetoing permissions
* the remainder of the string is the permission (possibly wildcarded, with :rw as optional suffix)

For example:

[source,ini]
----
user_role   = !reg/org.estatio.api,\
              !reg/org.estatio.webapp.services.admin,\
              reg/* ; \
api_role    = org.estatio.api ;\
admin_role = adm/*
----

sets up:
* the user role with access to all permissions except those in `org.estatio.api` and `org.estatio.webapp.services.admin`
* the api_role with access to all permissions in `org.estatio.api`
* the admin_role with access to everything.

The permission group concept is required to scope the applicability of any veto permission. This is probably best explained by an example. Suppose that a user has both `admin_role` and `user_role`; we would want the `admin_role` to trump the vetos of the `user_role`, in other words to give the user access to everything. Because of the permission groups, the two `!reg/...` vetos in user_role only veto out selected permissions granted by the `reg/*` permissions, but they do not veto the permissions granted by a different scope, namely `adm/*`. The net effect is what we would want: that a user with both `admin_role` and `user_role` would have access to everything, irrespective of those two veto permissions of the `user_role`.

To tell Shiro to use the Isis permission format, add the following to `shiro.ini`:

[source,ini]
----
permissionResolver = org.apache.isis.security.shiro.authorization.IsisPermissionResolver
xxxRealm.permissionResolver = $permissionResolver
----

where `xxxRealm` is the realm to be configured.



== Multiple Realms

A more sophisticated approach is to use external realms. For example, to configure two text-based realms defined, `realm1` and `realm2`, we would define a `resourcePath` for each, in the form:

[source,ini]
----
realm1.resourcePath=classpath:webapp/realm1.ini
----

that is, the `src/main/resources/webapp/realm1.ini` file in the webapp project.

The security manager for the app would then be told to use these two realms:

[source,ini]
----<commit_msg>ISIS-1133: fixing issue with adoc formatting.<commit_after>= Configuring Shiro
: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.
:_basedir: ../
:_imagesdir: images/


Apache Isis' security mechanism is configurable, specifying an `Authenticator` and an `Authorizor` (non-public) APIs.  The Shiro security mechanism is an integration wih Apache Shiro that implements both interfaces.

[TIP]
====
The <<_simpleapp_archetype, SimpleApp archetype>> is pre-configured to use Apache Shiro, so much of what follows is set up already.
====

== Specifying Shiro as the security mechanism

To tell Apache Isis to use Shiro, update the `WEB-INF/isis.properties` file:

[source,ini]
----
isis.authentication=shiro
isis.authorization=shiro
----

This installs the appropriate implementation (the `ShiroAuthenticatorOrAuthorizor` class) that use Shiro's APIs to perform authentication and authorization.




== Bootstrapping Shiro

The Shiro environment (in essence, thread-locals holding the security credentials) needs to be bootstrapped using the following settings in the `WEB-INF/web.xml` file:

[source,xml]
----
<listener>
    <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>

<filter>
    <filter-name>ShiroFilter</filter-name>
    <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>ShiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
----

Based on this Shiro will then read `WEB-INF/shiro.ini` file to configure its Realm definitions for authentication and authorization.




== `WEB-INF/shiro.ini`

The `shiro.ini` file (at least as configured in the <<_simpleapp_archetype, SimpleApp archetype>>) is configured to use the built-in `$iniRealm`.  This is achieved by the line:

[source,ini]
----
securityManager.realms = $iniRealm
----

The file also (by way of example) include entries to setup an ldapRealm, but this is not wired in. For more information on LDAP, see link:./using-ldap.html[here].

Specifying `$iniRealm` means that the usernames/passwords, roles and permissions are read from the `shiro.ini` file itself.

* the users/passwords and their roles from the `[users]` sections;
* the roles are mapped to permissions in the `[roles]` section.


=== Users section

The `[users]` section lists users, passwords and their roles. For example:

[source,ini]
----
sven = pass, admin_role
dick = pass, user_role, analysis_role, self-install_role
bob  = pass, user_role, self-install_role
----

=== Roles section

The `roles` section lists roles and their corresponding permissions. For example:

[source,ini]
----
user_role = *:ToDoItems:*:*,\
            *:ToDoItem:*:*,\
            *:ToDoAppDashboard:*:*
analysis_role = *:ToDoItemAnalysis:*:*,\
            *:ToDoItemsByCategoryViewModel:*:*,\
            *:ToDoItemsByDateRangeViewModel:*:*
self-install_role = *:ToDoItemsFixturesService:install:*
admin_role = *
----

=== Permissions format

The permission format is configurable. The default format is:

[source,ini]
----
packageName:className:memberName:r,w
----

where:

* `memberName` is the property, collection or action name.
* `r` indicates that the member is visible
* `w` indicates that the member is usable (editable or invokable)

and where each of the parts of the permission string can be wildcarded using `*`.

Because these are wildcards, a '*' can be used at any level. Additionally, missing levels assume wildcards.  Thus:

[source]
----
com.mycompany.myapp:Customer:firstName:r,w   # view or edit customer's firstName
com.mycompany.myapp:Customer:lastName:r      # view customer's lastName only
com.mycompany.myapp:Customer:placeOrder:*    # view and invoke placeOrder action
com.mycompany.myapp:Customer:placeOrder      # ditto
com.mycompany.myapp:Customer:*:r             # view all customer class members
com.mycompany.myapp:*:*:r                    # view-only access for all classes in myapp package
com.mycompany.myapp:*:*:*                    # view/edit for all classes in myapp package
com.mycompany.myapp:*:*                      # ditto
com.mycompany.myapp:*                        # ditto
com.mycompany.myapp                          # ditto
*                                            # view/edit access to everything
----




==== Using the Enhanced Isis Permission Syntax

Shiro also allows the conversion to be mapped to alternative `Permission` instances; Isis provides its own `IsisPermission` which provides an extended and more flexible syntax.


Isis defines its own extended syntax for permissions, following the format:

[source,ini]
----
([!]?)([^/]+)[/](.+)
----

where:

* the optional `!` prefix indicates this permission is a vetoing permission
* the optional `xxx/` prefix is a permission group that scopes any vetoing permissions
* the remainder of the string is the permission (possibly wildcarded, with :rw as optional suffix)

For example:

[source,ini]
----
user_role   = !reg/org.estatio.api,\
              !reg/org.estatio.webapp.services.admin,\
              reg/* ; \
api_role    = org.estatio.api ;\
admin_role = adm/*
----

sets up:
* the user role with access to all permissions except those in `org.estatio.api` and `org.estatio.webapp.services.admin`
* the api_role with access to all permissions in `org.estatio.api`
* the admin_role with access to everything.

The permission group concept is required to scope the applicability of any veto permission. This is probably best explained by an example. Suppose that a user has both `admin_role` and `user_role`; we would want the `admin_role` to trump the vetos of the `user_role`, in other words to give the user access to everything. Because of the permission groups, the two "+++!reg/...+""" vetos in user_role only veto out selected permissions granted by the "+++reg/*+++" permissions, but they do not veto the permissions granted by a different scope, namely "+++adm/*+++". The net effect is what we would want: that a user with both `admin_role` and `user_role` would have access to everything, irrespective of those two veto permissions of the `user_role`.

To tell Shiro to use the Isis permission format, add the following to `shiro.ini`:

[source,ini]
----
permissionResolver = org.apache.isis.security.shiro.authorization.IsisPermissionResolver
xxxRealm.permissionResolver = $permissionResolver
----

where `xxxRealm` is the realm to be configured.



== Multiple Realms

A more sophisticated approach is to use external realms. For example, to configure two text-based realms defined, `realm1` and `realm2`, we would define a `resourcePath` for each, in the form:

[source,ini]
----
realm1.resourcePath=classpath:webapp/realm1.ini
----

that is, the `src/main/resources/webapp/realm1.ini` file in the webapp project.

The security manager for the app would then be told to use these two realms:

[source,ini]
----
{'fraction_non_alphanumeric': 0.09820367190595694, 'fraction_numerical': 0.0014529124290054154, 'mean_word_length': 3.8597560975609757, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '539885', 'n_tokens_mistral': 4317, 'n_tokens_neox': 4199, 'n_words': 1705}