blob: c108bac94316a285b05b73921f4f88a9e0d05469 [file] [log] [blame]
///////////////////////////////////////////////////////////////
* 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.
///////////////////////////////////////////////////////////////
[[library-shiro, Shiro Security Library]]
= Shiro Security =
[devstatus]
--------------
source=libraries/shiro-core/dev-status.xml
--------------
This library provides integration with the http://shiro.apache.org/[Apache Shiro] Java Security Framework.
NOTE: If you are working on a HTTP based application, see the <<library-shiro-web>> that leverages this very library
and is directly usable with the <<library-http>>, the <<library-servlet>> or any other Servlet based stack.
``Apache Shiro is a powerful and easy-to-use Java security framework that performs authentication, authorization,
cryptography, and session management. With Shiro’s easy-to-understand API, you can quickly and easily secure any
application – from the smallest mobile applications to the largest web and enterprise applications.'' says the Apache
Shiro website.
Altough Apache Shiro can be used as-is with Zest™ Applications, this library provides integrations that can come in
handy. If your use case do not fit any of theses integrations, look at their respective code. You should find out
pretty easily how to compose the provided code to write your integration. Don't hesitate to contribute interesting
integrations to this very library.
We invite you to read the comprehensive http://shiro.apache.org/documentation.html[Apache Shiro documentation], we will
mostly discuss Zest™ related matters here.
include::../../build/docs/buildinfo/artifact.txt[]
== Basic usage ==
For standalone applications, you can use plain Shiro easily. The only thing to do is to register a configured
SecurityManager when activating your Zest™ Application. It can be done outside the application, before its activation,
"à là" by-hand ;
[snippet,java]
----
source=libraries/shiro-core/src/test/java/org/apache/zest/library/shiro/StandaloneShiroTest.java
tag=before
----
note that this example code register the SecurityManager as a VM static singleton.
However we recommend to use the provided IniSecurityManagerService that does exactly this when activated and unregister
the SecurityManager when passivated:
[snippet,java]
----
source=libraries/shiro-core/src/test/java/org/apache/zest/library/shiro/StandaloneShiroTest.java
tag=assembly
----
You can change the INI resource path through the ShiroIniConfiguration:
[snippet,java]
----
source=libraries/shiro-core/src/main/java/org/apache/zest/library/shiro/ini/ShiroIniConfiguration.java
tag=config
----
Remember that this setup use a ThreadLocal SecurityManager singleton. Among other things it means that, althoug the
IniSecurityManagerService is activated on Application activation, if you need to use Shiro in other Services that are
activated on Application activation you should tell Zest™ about this dependency by injecting the SecurityManagerService
in the laters.
Once started you must remember to register the SecurityManager in Shiro's ThreadContext ;
[snippet,java]
----
source=libraries/shiro-core/src/test/java/org/apache/zest/library/shiro/StandaloneShiroTest.java
tag=thread-context
----
that's how Shiro works.
== Security Concern ==
This library provides the `SecurityConcern` that should be used alongside the provided method annotations that mimic
Apache Shiro annotations:
- The `@RequiresAuthentication` annotation requires the current Subject to have been authenticated during their current
session for the annotated class/instance/method to be accessed or invoked.
- The `@RequiresGuest` annotation requires the current Subject to be a "guest", that is, they are not authenticated or
remembered from a previous session for the annotated class/instance/method to be accessed or invoked.
- The `@RequiresPermissions` annotation requires the current Subject be permitted one or more permissions in order to
execute the annotated method.
- The `@RequiresRoles` annotation requires the current Subject to have all of the specified roles. If they do not have
the role(s), the method will not be executed and an AuthorizationException is thrown.
- The `@RequiresUser` annotation requires the current Subject to be an application user for the annotated
class/instance/method to be accessed or invoked. An 'application user' is defined as a Subject that has a known
identity, either known due to being authenticated during the current session or remembered from 'RememberMe' services
from a previous session.
== Realms Services ==
All the above is sufficient as long as you use the ini file to store user credentials and permissions or a Realm that
has no dependency on your application code and can be specified in the ini file to be instanciated by Shiro outside the
Zest™ scope.
One usecase where it's not sufficient comes quickly as you would like to provide user credentials and permissions
from Entities stored in an EntityStore or perform any custom logic involving your Zest™ Application.
Let's look at a complete example using a Realm Service that extends one of the Shiro provided Realm which use in-memory
credientials and configuring it ;
[snippet,java]
----
source=libraries/shiro-core/src/test/java/org/apache/zest/library/shiro/RealmServiceTest.java
tag=realm-service
----
We start by defining a Realm Service and its Mixin that's based on SimpleAccountRealm that we configure to handle hashed
passwords. For the sake of the example it is shown how to hash a password using Shiro built in mecanisms. Then comes
the Assembly where we simply reuse the Standalone Shiro Assembly and declare our Realm as a Service. It works the same
way when using the <<library-shiro-web>>.
Note that under the hood, assembled Realm Services are added to the ones configured in the INI file.
== Security Domain ==
Going further, if you want to persist credentials and permissions in an EntityStore, the Shiro Security Library
provides skeletons to easily setup some usecases consisting of Shiro setup facilities and base state model for you to
compose with.
=== Passwords ===
Password storage is not a simple subject. Shiro provide best practice mecanisms using salt and repeated-hashing out of
the box. It is possible to setup your Realm so that hashed passwords are stored in a future proof manner, meaning that
you can change the used algorithms while retaining compatibility with passwords already stored.
Shiro use the
http://shiro.apache.org/static/current/apidocs/org/apache/shiro/crypto/hash/format/Shiro1CryptFormat.html[Shiro1CryptFormat]
which is a fully reversible http://packages.python.org/passlib/modular_crypt_format.html[Modular Crypt Format] (MCF).
This library provides a `PasswordRealmService` to be used with a `PasswordSecurable`. Let's look at a complete
example.
First you need to define your User (or Account, or whatever fits your domain), for the sake of the example we define a
UserFactory too. Note that the factory uses the PasswordService implemented by the PasswordRealm to hash the password:
[snippet,java]
----
source=libraries/shiro-core/src/test/java/org/apache/zest/library/shiro/PasswordDomainTest.java
tag=domain
----
Now comes the assembly that reuse what's described above and add both the password domain assembly plus your custom User
entity and its factory:
[snippet,java]
----
source=libraries/shiro-core/src/test/java/org/apache/zest/library/shiro/PasswordDomainTest.java
tag=assembly
----
And finally here is how to create a new user and below how to perform a login:
[snippet,java]
----
source=libraries/shiro-core/src/test/java/org/apache/zest/library/shiro/PasswordDomainTest.java
tag=usage
----
In this setup, password hashing use the Shiro's default (Salted SHA-256 with 500.000 iterations). If you _need_ to
change this you can do it using PasswordRealmConfiguration properties:
[snippet,java]
----
source=libraries/shiro-core/src/main/java/org/apache/zest/library/shiro/domain/passwords/PasswordRealmConfiguration.java
tag=config
----
=== Permissions & Roles ===
In the same vein, this library provide a domain state skeleton with support in `PasswordRealmService`. It allows you to
easily store roles, permissions and assignment to your accounts.
Let's look at the previous example with permissions added.
First you need to add the RoleAssignee type to your account:
[snippet,java]
----
source=libraries/shiro-core/src/test/java/org/apache/zest/library/shiro/PermissionsDomainTest.java
tag=domain
----
Assembly is straight forward:
[snippet,java]
----
source=libraries/shiro-core/src/test/java/org/apache/zest/library/shiro/PermissionsDomainTest.java
tag=assembly
----
And here is how to use all this:
[snippet,java]
----
source=libraries/shiro-core/src/test/java/org/apache/zest/library/shiro/PermissionsDomainTest.java
tag=usage
----
== Other authentication mecanisms ==
For other authentication mecanisms you can leverage Shiro extensions available in the Shiro distribution or as external
libraries. There's support for text files, simple JDBC, LDAP, CAS SSO, OAuth, OpenID, X.509 Certificates etc...
Take the PasswordRealmService as a start and extend/rewrite it to suit your needs.
If you happen to come with a Zest™ integration that could be valuable in this very library, don't hesitate to
contribute.
== Logging ==
All code from this library use the `org.apache.zest.library.shiro` logger.