This module, intended for use within Apache Isis, provides the ability to manage *user*s, *role*s, and *permission*s. Users have roles, roles have permissions, and permissions are associated with *application feature*s. These features are derived from the Isis metamodel and can be scoped at either a package, class or individual class member. Permissions themselves can either allow or veto the ability to view or change any application feature.
A key design objective of this module has been to limit the amount of permissioning data required. To support this objective:
-
permissions are hierarchical: a class-level permission applies to all class members, while a package-level permission applies to all classes of all subpackages
-
permissions can allow or veto access; thus a role can be granted access to most features, but excluded from selective others
-
permissions are scoped: a member-level permission overrides a class-level permission, a class-level permission overrides a package-level permission; the lower-level package permission overrides a higher-level one (eg
com.mycompany.invoicing
overridescom.mycompany
). -
if there are conflicting permissions at the same scope, then the allow takes precedence over the veto.
The module also supports multi-tenancy, whereby a user can be prevented from either viewing or modifying objects to which they don’t have access ("don’t belong to them").
-
In the original design of this module, this was based on the concept of a hierarchical tenancy, each of which is identified by an application tenancy path ("atPath") and the interpretation of which was hard-coded into the module. For example, users would typically have the ability to view/edit data in "their" tenancy or sub-tenancies, could view data in parent tenancies (for example, global reference data/standing data), and would have no access to any peer entities.
-
As of v1.13.3, this has been generalized; the interpretation of the "atPath" is entirely application-specific (with legacy support for the original design).
-
As of v1.13.6, this has been generalized further; an
ApplicationUser
's "atPath" is no longer a reference to a particularApplicationTenancy
entity; it is simply a string. That string could of course still be used to represent the identifier of a singleApplicationTenancy
, but it need not: it should be thought of instead as encoding and and all characteristics of the user or domain object which pertain to determining visibility/editability. TheApplicationTenancy
entity has been retained only to make it easier to migrate to this more generalized model.
The module also provides an implementation of Apache Shiro's AuthorizingRealm. This allows the users/permissions to be used for Isis' authentication and/or authorization.
Authentication is optional; each user is either local or delegated:
-
users with a delegated account type are authenticated through a (configured) delegated authentication realm (for example LDAP). Any other implementation of Shiro’s
AuthenticatingRealm
can be used. -
users with a local account type are authenticated through a
PasswordEncryptionService
.
The module provides a default implementation based on jBCrypt, but other implementations can be plugged-in if required.
The above diagram was generated by yuml.me.
The following screenshots show an example app’s usage of the module, which includes all the services and entities (users, roles, permissions etc) provided by the module itself.
This example app’s domain also has its own very simple ExampleEntity
entity and corresponding repository.
For further screenshots, see the screenshot tutorial on the wiki.
When the security module starts up, it will automatically (idempotently) seed a number of roles, corresponding permissions and a default isis-module-security-admin
user.
This user has access to the security menu:
One of the roles granted to the isis-module-security-admin
user is the corresponding (similarly named) isis-module-security-admin
role.
It is this that grants all permissions to all classes in the security module itself:
The isis-module-security-regular-user
role grants selected permissions to viewing/changing members of the ApplicationUser
class (so that a user with this role can view/update their own record):
Permissions can be created at different scopes or levels (highlighted in the above screenshot).
-
Permissions created at the package level apply to all classes in all packages and subpackages (that is, recursively).
-
Permissions defined at the class level take precedence to those defined at the package level.
For example, a user might have allow/viewing at a parent level, but have this escalated to allow/changing for a particular class. Conversely, the class-level permission might veto access.
Permissions can also be defined the member level: action, property or collection. These override permissions defined at either the class- or package-level.
Permissions can either grant (allow) access or prevent (veto) access. If a user has permissions that contradict each other (for example, they are a member of "roleA" that allows the permission, but also of "roleB" that vetoes the permission) then by default the allow wins. However, this is strategy is pluggable, and the security module can be configured such that a veto would override an allow if required.
For a property, "changing" means being able to edit it. For a collection, "changing" means being able to add or remove from it. For an action, "changing" means being able to invoke it.
Note that Isis' Wicket viewer currently does not support the concept of "changing" collections; the work-around is instead create a pair of actions to add/remove instead. This level of control is usually needed anyway.
An allow/changing permission naturally enough implies allow/viewing, while conversely and symmetrically veto/viewing permission implies veto/changing.
The list of packages (or classes, or class members) is derived from Isis' own metamodel.
Application users can have either a local or a delegated account type.
-
Local users are authenticated and authorized through the module’s Shiro realm implementation. The users are created explicitly by the administrator.
-
Optionally a delegate authentication realm can be configured; if so then delegated users can be created and their credentials will be authenticated by the delegate authentication realm. By default, users are created automatically when that user attempts to log in (though this feature can be disabled, see below) However, for safety their
ApplicationUser
accounts are created in a disabled state and with no roles, so the administrator is still required to update them.
Once the user is created, then additional information about that user can be captured, including their name and contact details. This information is not otherwise used by the security module, but may be of use to other parts of the application. The users' roles and effective permissions are also shown.
A user can maintain their own details, but may not alter other users' details. An administrator can alter all details, as well as reset a users' password.
If a user is disabled, then they may not log in. This is useful for temporarily barring access to users without having to change all their roles, for example if they leave the company or go on maternity leave.
Apache Isis allows users to sign-up (self-register) with an application provided that:
-
the application is correctly configured for the
EmailNotificationService
, by specifyingisis.service.email.sender.address
andisis.service.email.sender.password
configuration properties; and -
the application provides an implementation of the
UserRegistrationService
(more on this below).
The sign-up link is shown on the initial login page:
Following the link prompts for an email:
An email is sent to the specified address, with a link to complete the registration:
Completing registration consists of selecting a username and password:
The user can then login:
In the screenshot above note that the user has a default set of permissions.
These are set up by the UserRegistrationService
implementation.
The security module provides SecurityModuleAppUserRegistrationServiceAbstract
which provides most of the implementation of this service; the demo app’s AppUserRegistrationService
service completes the implementation by specifying the role(s) to assign any new users:
@DomainService
public class AppUserRegistrationService extends SecurityModuleAppUserRegistrationServiceAbstract {
protected ApplicationRole getInitialRole() {
return findRole(ExampleFixtureScriptsRoleAndPermissions.ROLE_NAME);
}
protected Set<ApplicationRole> getAdditionalInitialRoles() {
return Collections.singleton(findRole(ExampleRegularRoleAndPermissions.ROLE_NAME));
}
private ApplicationRole findRole(final String roleName) {
return applicationRoles.findRoleByName(roleName);
}
@Inject
private ApplicationRoles applicationRoles;
}
So, for the demo app at least, any new user has access to the "example-fixture-scripts" role (= the Prototyping menu) and to the "example-regular-role" (= the Tenanted Entities and the Non-Tenanties Entities menus).
Speaking of which…
Application tenancy is the concept of determining which application users can see/modify domain objects.
For this to work, there needs to be a application-specific mechanism for making the decision.
This is defined by the (optional) ApplicationTenancyEvaluator
SPI service:
public interface ApplicationTenancyEvaluator {
boolean handles(Class<?> cls); // (1)
String hides(Object domainObject, ApplicationUser applicationUser); // (2)
String disables(Object domainObject, ApplicationUser applicationUser); // (3)
}
-
Whether this evaluator can determine the tenancy of the specified domain entity being interacted with (the "what").
-
Whether this instance of the domain object can be viewed by the user. Any non-null string is interpreted as meaning that the object should be hidden from view
-
Whether this instance of the domain object can be modifed by the user; a non-null return value is interpreted as the reason it is read-only.
Note
|
This demo app demonstrates how this can work for an application where the name of each object is correlated to the roles of the user. |
The security module also provides its own built-in mechanism for determining application tenancy, through the concept of the application tenancy path ("atPath").
Note
|
This is this design is designed for hierarchical tenancies, eg where a tenancy corresponds to a country or region and a user cannot reside in multiple regions concurrently.
If this does not suit your requirements, then use the more general purpose |
Both application users and domain objects can have an "at path", this is expected to identify a single ApplicationTenancy
entity.
For application user’s this is simply a property of the object, for domain object’s this is performed by implementing the HasAtPath
interface:
public interface HasAtPath {
String getAtPath();
}
The application can then be configured so that access to domain objects can be restricted based on the respective tenancies of the user accessing the object and of the object itself. The table below summarizes the rules:
object’s tenancy | user’s tenancy | visible? | editable? |
---|---|---|---|
null |
null |
Y |
Y |
null |
non-null |
Y |
Y |
/ |
/ |
Y |
Y |
/ |
/it |
Y |
|
/ |
/it/car |
Y |
|
/ |
/it/igl |
Y |
|
/ |
/fr |
Y |
|
/ |
null |
||
/it |
/ |
Y |
Y |
/it |
/it |
Y |
Y |
/it |
/it/car |
Y |
|
/it |
/it/igl |
Y |
|
/it |
/fr |
||
/it |
null |
||
/it/car |
/ |
Y |
Y |
/it/car |
/it |
Y |
Y |
/it/car |
/it/car |
Y |
Y |
/it/car |
/it/igl |
||
/it/car |
/fr |
||
/it/car |
null |
To enable this requires a single configuration property to be set, see below.
You may not wish to have your domain objects implement the WithApplicationTenancy
.
As all that is required is to determine the application "path" of a domain object, an alternative is to provide an implementation of the ApplicationTenancyPathEvaluator
SPI service.
This is defined as:
public interface ApplicationTenancyPathEvaluator {
boolean handles(Class<?> cls); // (1)
String applicationTenancyPathFor(final Object domainObject); // (2)
}
-
indicates if the domain object’s class has multi-tenancy
-
the method that actually returns the path.
For example, the todoapp provides an implementation for its ToDoItem
:
@DomainService(
nature = NatureOfService.DOMAIN
)
public class ApplicationTenancyPathEvaluatorForToDoApp implements ApplicationTenancyPathEvaluator {
@Override
public boolean handles(final Class<?> cls) {
return ToDoItem.class == cls;
}
@Override
public String applicationTenancyPathFor(final Object domainObject) {
// always safe to do, per the handles(...) method earlier
final ToDoItem toDoItem = (ToDoItem) domainObject;
return toDoItem.getAtPath();
}
}
The evaluator can also optionally handle and return a path for the security domain module’s own ApplicationUser
entity; but if it does not, then the user’s own tenancy (ApplicationUser#getTenancy()
) is used instead.
The prerequisite software is:
-
Java JDK 8 (>= 1.9.0) or Java JDK 7 (<= 1.8.0)
-
note that the compile source and target remains at JDK 7
-
-
maven 3 (3.2.x is recommended).
To build the demo app:
git clone https://github.com/isisaddons/isis-module-security.git
mvn clean install
To run the demo app:
cd webapp
mvn jetty:run
Then log on using user: isis-module-security-admin
, password: pass
You can either use this module "out-of-the-box", or you can fork this repo and extend to your own requirements.
Update your classpath by adding this dependency in your dom project’s pom.xml
:
<dependency>
<groupId>org.isisaddons.module.security</groupId>
<artifactId>isis-module-security-dom</artifactId>
<version>1.14.0</version>
</dependency>
If using the PasswordEncryptionServiceUsingJBcrypt
service (discussed below), also add a dependency on the underlying
jbcrypt
library:
<dependency>
<groupId>org.mindrot</groupId>
<artifactId>jbcrypt</artifactId>
<version>0.3m</version>
</dependency>
Check for later releases by searching [Maven Central Repo](http://search.maven.org/#search|ga|1|isis-module-security-dom).
The module includes org.isisaddons.module.security.shiro.IsisModuleSecurityRealm
, an implementation of Apache Shiro’s org.apache.shiro.realm.AuthorizingRealm
class.
This realm is intended to be configured as the single realm for Shiro, but it can optionally have a delegateAuthenticationRealm injected into it.
-
if configured without a delegate realm then
IsisModuleSecurityRealm
deals only with local users and performs both authentication and authorization for them. Authentication is performed against encrypted password. Users with delegate account type will be unable to log in. -
if configured with a delegate realm then
IsisModuleSecurityRealm
deals with both delegated and local users. Authentication of delegated users is performed by the delegate authentication realm, while local users continue to be authenticated in the same way as before, against their encrypted password. Authorization is performed the same way for either account type, by reference to their user roles and those roles' permissions.
For both local and delegated users the realm will prevent a disabled user from logging in.
To configure, update your WEB-INF/shiro.ini’s `[main]
section:
[main]
isisModuleSecurityRealm=org.isisaddons.module.security.shiro.IsisModuleSecurityRealm
authenticationStrategy=org.isisaddons.module.security.shiro.AuthenticationStrategyForIsisModuleSecurityRealm
securityManager.authenticator.authenticationStrategy = $authenticationStrategy
securityManager.realms = $isisModuleSecurityRealm
If a delegate authentication realm is used, then define it and inject (again, in the [main]
section):
someOtherRealm=... # (1)
isisModuleSecurityRealm.delegateAuthenticationRealm=$someOtherRealm
-
the
someOtherRealm
variable defines some other realm to perform authentication.
To disable the automatic creation of delegate users, use:
isisModuleSecurityRealm.autoCreateUser=false
If using an AppManifest
, then update its getModules()
method and also its getAdditionalServices()
method:
@Override
public List<Class<?>> getModules() {
return Arrays.asList(
...
org.isisaddons.module.security.SecurityModule.class,
);
}
@Override
public List<Class<?>> getAdditionalServices() {
return Arrays.asList(
org.isisaddons.module.security.dom.password.PasswordEncryptionServiceUsingJBcrypt.class // (1)
,org.isisaddons.module.security.dom.permission.PermissionsEvaluationServiceAllowBeatsVeto.class // (2)
);
}
-
is an implementation of the
PasswordEncryptionService
. This is mandatory; local users (including the defaultisis-module-security-admin
administrator user) must be authenticated using the password service. If required, any other implementation can be supplied. -
is an implementation of the
PermissionsEvaluationService
that determines how to resolve conflicting permissions at the same scope. This service is optional; if not presentthen the module will default to an allow-beats-veto strategy. An alternative implementation ofPermissionsEvaluationServiceVetoBeatsAllow
is also available for use if required; or any other implementation of this interface can be supplied.
There is further discussion of the PasswordEncryptionService
and PermissionsEvaluationService
below.
If you aren’t using an AppManifest
, instead update your WEB-INF/isis.properties
:
isis.services-installer=configuration-and-annotation
isis.services.ServicesInstallerFromAnnotation.packagePrefix=
...,\
org.isisaddons.module.security,\
...
isis.services = ...,\
org.isisaddons.module.security.dom.password.PasswordEncryptionServiceUsingJBcrypt,\
org.isisaddons.module.security.dom.permission.PermissionsEvaluationServiceAllowBeatsVeto,\
...
Note
|
The security module automatically seeds users and roles, using fixture scripts.
As of |
To enable tenancy checking (as described above, to restrict a user’s access to tenanted objects), then a configuration property must be added.
This can either be specified in the AppManifest
or in WEB-INF/isis.properties
.
If using an AppManifest
, then update its getConfigurationProperties()
method:
@Override
public Map<String, String> getConfigurationProperties() {
return ImmutableMap.of(
"isis.reflector.facets.include", "org.isisaddons.module.security.facets.TenantedAuthorizationFacetFactory");
}
Alternatively, if using isis.properties
, then define:
isis.reflector.facets.include=org.isisaddons.module.security.facets.TenantedAuthorizationFacetFactory
The actions for the security module do not include font-awesome icons by default; you will most likely want to choose your own icons.
The easiest way to do this is using the isis.reflector.facet.cssClassFa.patterns
configuration property which uses the name of the action methods to associate an appropriate font-awesome icon.
The action names defined by the domain objects within the security module use the following naming conventions:
-
newXxx
- create a new persisted object -
findXxx
- find an existing object -
updateXxx
- update an existing object -
deleteXxx
- delete an existing object -
addXxx
- add an existing object to a collection of another -
removeXxx
- remove an object from a collection -
allXxx
- for prototyping actions
There are also some other miscellaneous action names, eg:
-
lock
- lock a user (to prevent that user from logging in) -
unlock
- unlock a user so that they can login -
resetPassword
- allow an administrator to reset the password for a user -
me
- to lookup theApplicationUser
entity for the currently logged-in user
For example, define the following configuration property:
isis.reflector.facet.cssClassFa.patterns=\
new.*:fa-plus,\
add.*:fa-plus-square,\
create.*:fa-plus,\
update.*:fa-edit,\
remove.*:fa-minus-square,\
find.*:fa-search,\
all.*:fa-list
By default the module’s entities will be installed in the isissecurity
schema.
This is hard-coded in their annotations.
This can be overridden by creating a .orm
file.
For example, to change the ApplicationUser
table to reside in the "dbo" schema (to run on SQL Server, say), create an ApplicationUser-sqlserver.orm
file.
This should reside in the org.isisaddons.module.security.dom.user
package:
<?xml version="1.0" encoding="UTF-8" ?>
<orm xmlns="http://xmlns.jcp.org/xml/ns/jdo/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/jdo/orm
http://xmlns.jcp.org/xml/ns/jdo/orm_3_0.xsd">
<package name="org.isisaddons.module.security.dom.user">
<class name="ApplicationUser"
schema="dbo">
</class>
</package>
Then, in persistor.properties
, add:
isis.persistor.datanucleus.impl.datanucleus.Mapping=sqlserver
This will cause DataNucleus to also search for ApplicationUser-sqlserver.orm
files and use them if found.
To run the demo application against SQL Server (as opposed to inmemory):
-
create a new and empty database, eg
securitydemo
, with corresponding user and password -
edit the
webapp/pom.xml
to include the sqljdbc4 driver -
edit the JDBC properties in
persistor.properties
file:isis.persistor.datanucleus.impl.javax.jdo.option.ConnectionDriverName=com.microsoft.sqlserver.jdbc.SQLServerDriver isis.persistor.datanucleus.impl.javax.jdo.option.ConnectionURL=jdbc:sqlserver://127.0.0.1.1533;instance=.;databaseName=securitydemo isis.persistor.datanucleus.impl.javax.jdo.option.ConnectionUserName=securitydemo isis.persistor.datanucleus.impl.javax.jdo.option.ConnectionPassword=pass
-
configure to auto-create schema/tables in empty database, by adding to
persistor_datanucleus.properties
:isis.persistor.datanucleus.impl.datanucleus.schema.autoCreateAll=true isis.persistor.datanucleus.impl.datanucleus.schema.validateTables=true isis.persistor.datanucleus.impl.datanucleus.schema.validateConstraints=true
If you want to use the current -SNAPSHOT
, then the steps are the same as above, except:
-
when updating the classpath, specify the appropriate -SNAPSHOT version:
<version>1.15.0-SNAPSHOT</version>
-
add the repository definition to pick up the most recent snapshot (we use the Cloudbees continuous integration service). We suggest defining the repository in a
<profile>
:<profile> <id>cloudbees-snapshots</id> <activation> <activeByDefault>true</activeByDefault> </activation> <repositories> <repository> <id>snapshots-repo</id> <url>http://repository-estatio.forge.cloudbees.com/snapshot/</url> <releases> <enabled>false</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories> </profile>
If instead you want to extend this module’s functionality, then we recommend that you fork this repo. The repo is structured as follows:
-
pom.xml
- parent pom -
app
- the module implementation, depends ondom
andfixture
-
dom
- the module implementation, depends on Isis applib -
fixture
- fixtures, holding a sample domain objects and fixture scripts; depends ondom
-
integtests
- integration tests for the module; depends onapp
-
webapp
- demo webapp (see above screenshots); depends onapp
Only the dom
project is released to Maven Central Repo.
The versions of the other modules are purposely left at 0.0.1-SNAPSHOT
because they are not intended to be released.
The module defines a number of services and default implementations. The behaviour of the module can be adjusted by implementing and registerng alternative implementations.
The PasswordEncryptionService
(responsible for authenticating local user accounts) is responsible for performing a one-way encryption of password to encrypted form.
This encrypted version is then stored in the ApplicationUser
entity’s encryptedPassword
property.
The service defines the following API:
public interface PasswordEncryptionService {
public String encrypt(final String password);
public boolean matches(final String candidate, final String encrypted);
}
The PasswordEncryptionServiceUsingJbcrypt
provides an implementation of this service based on Blowfish algorithm.
It depends in turn on org.mindrot:jbcrypt
library; see above for details of updating the classpath to reference this library.
The PermissionsEvaluationService
is responsible for determining which of a number of possibly conflicting permissions apply to a target member.
It defines the following API:
public interface PermissionsEvaluationService {
public ApplicationPermissionValueSet.Evaluation evaluate(
final ApplicationFeatureId targetMemberId,
final ApplicationPermissionMode mode,
final Collection<ApplicationPermissionValue> permissionValues);
It is not necessary to register any implementation of this service in isis.properties
; by default a strategy of allow-beats-veto is applied.
However this strategy can be explicitly specified by registering the (provided) PermissionsEvaluationServiceAllowBeatsVeto
implementation, or alternatively it can be reversed by registering PermissionsEvaluationServiceVetoBeatsAllow
.
Of course some other implementation with a different algorithm may instead be registered.
Whenever the application starts the security module checks for (and creates if missing) the following roles, permissions and users:
-
isis-module-security-admin
role-
allow changing of all classes (recursively) under the
org.isisaddons.module.security.app
package -
allow changing of all classes (recursively) under the
org.isisaddons.module.security.dom
package
-
-
isis-module-security-regular-user
role-
allow changing (ie invocation) of the
org.isisaddons.module.security.app.user.MeService#me
action -
allow viewing of the
org.isisaddons.module.security.app.dom.ApplicationUser
class -
allow changing of the selected "self-service" actions of the
org.isisaddons.module.security.app.dom.ApplicationUser
class
-
-
isis-module-security-fixture
role-
allow changing of
org.isisaddons.module.security.fixture
package (run example fixtures if prototyping)
-
-
isis-module-security-admin
user-
granted
isis-module-security-admin
role
-
-
isis-applib-fixtureresults
role-
allow changing of
org.apache.isis.applib.fixturescripts.FixtureResult
class
-
This work is performed by the SeedSecurityModuleService
.
Limitations in current implementation:
-
It is not possible to set permissions on the root package. The workaround is to specify for
org
orcom
top-level package instead.
Ideas for future features:
-
enhance the auto-creation of delegated user accounts, so that an initial role can be assigned and the user left as enabled
-
users could possibly be extended to include user settings, refactored out from isis-module-settings
-
features could possibly be refactored out/merged with isis-module-devutils.
-
hierarchical roles
-
1.14.0
- released against Isis 1.14.0 -
1.13.6
- released against Isis 1.13.0, closes #47 (changeApplicationUser#getTenancy() to just `#getAtPath()
) and #51 (fixes breakage in 1.13.3 thru 1.13.5 where defaultApplicatoinTenancyPathEvaluator
not correctly installed) -
1.13.5
- released against Isis 1.13.0, closes #30 (clone user) and #49 (disable autocreate of delegate users) -
1.13.4
- released against Isis 1.13.0, closes #41 (action semantics) and #42 (bulk deletion of orphaned permissions) -
1.13.3
- released against Isis 1.13.0, closes #40 (generalizedApplicationTenancyPathEvaluator
SPI) -
1.13.2
- released against Isis 1.13.0, closes #39 (renameorphanedPermissions
tofindOrphanedPermissions
) -
1.13.1
- released against Isis 1.13.0, closes #38 (list all orphaned permissions) -
1.13.0
- released against Isis 1.13.0 -
1.12.2
- released against Isis 1.12.1; closes #32 (can’t create new user) -
1.12.1
- released against Isis 1.12.1; converted to use 1.12.x constructs -
1.12.0
- released against Isis 1.12.0 -
1.11.0
- released against Isis 1.11.0 -
1.10.0
- released against Isis 1.10.0 -
1.9.0
- released against Isis 1.9.0; closes #18, #17, #16, #15, #14, #13, #12 (mapping entities to 'isissecurity' schema); -
1.8.1
- released against Isis 1.8.0; closes #11. -
1.8.0
- released against Isis 1.8.0.ApplicationTenancy
extended to support hierarchical tenancies, with path as primary key (nb: breaking change), support to make easier to extend (pluggable factories and events for all actions). MeService on TERTIARY menuBar; #10 -
1.7.0
- released against Isis 1.7.0 -
1.6.2
- made more resilient so can be called by an application’s own 'security seed' service -
1.6.1
- support for account types and delegated authentication realm -
1.6.0
- first release
Copyright 2014-date Dan Haywood
Licensed 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.
Only the dom
module is deployed, and is done so using Sonatype’s OSS support (see user guide).
To deploy a snapshot, use:
pushd dom
mvn clean deploy
popd
The artifacts should be available in Sonatype’s Snapshot Repo.
If you have commit access to this project (or a fork of your own) then you can create interim releases using the interim-release.sh
script.
The idea is that this will - in a new branch - update the dom/pom.xml
with a timestamped version (eg 1.14.0.20170227-0738
).
It then pushes the branch (and a tag) to the specified remote.
A CI server such as Jenkins can monitor the branches matching the wildcard origin/interim/*
and create a build.
These artifacts can then be published to a snapshot repository.
For example:
sh interim-release.sh 1.14.0 origin
where
-
1.13.6
is the base release -
origin
is the name of the remote to which you have permissions to write to.
The release.sh
script automates the release process.
It performs the following:
-
performs a sanity check (
mvn clean install -o
) that everything builds ok -
bumps the
pom.xml
to a specified release version, and tag -
performs a double check (
mvn clean install -o
) that everything still builds ok -
releases the code using
mvn clean deploy
-
bumps the
pom.xml
to a specified release version
For example:
sh release.sh 1.14.0 \
1.15.0-SNAPSHOT \
dan@haywood-associates.co.uk \
"this is not really my passphrase"
where
* $1
is the release version
* $2
is the snapshot version
* $3
is the email of the secret key (~/.gnupg/secring.gpg
) to use for signing
* $4
is the corresponding passphrase for that secret key.
Other ways of specifying the key and passphrase are available, see the `pgp-maven-plugin’s documentation).
If the script completes successfully, then push changes:
git push origin master && git push origin 1.14.0
If the script fails to complete, then identify the cause, perform a git reset --hard
to start over and fix the issue before trying again.
Note that in the dom’s `pom.xml
the nexus-staging-maven-plugin
has the autoReleaseAfterClose
setting set to true
(to automatically stage, close and the release the repo).
You may want to set this to false
if debugging an issue.
According to Sonatype’s guide, it takes about 10 minutes to sync, but up to 2 hours to update search.