Merge remote-tracking branch 'privilege/develop' into develop

This commit is contained in:
Robert von Burg 2016-06-24 17:39:50 +02:00
commit bf26f2c087
76 changed files with 10845 additions and 0 deletions

View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

View File

@ -0,0 +1,95 @@
ch.eitchnet.privilege
==================
[![Build Status](http://jenkins.eitchnet.ch/buildStatus/icon?job=ch.eitchnet.privilege)](http://jenkins.eitchnet.ch/view/ch.eitchnet/job/ch.eitchnet.privilege/)
Overview
=======================================================================
Privilege is a light weight library to secure access or grant privileges to
users in an application. Privilege allows a developer to secure the application
in different levels of the application providing API's for different
contexts.
Privilege is implemented in the Java language and is light weight in that it has
no external dependencies other than a Java runtime environment version 6. Since
the JRE 6 has an LDAP implementation it is possible to store Privilege data in
a LDAP repository with only the Privilege JAR.
Privilege is distributed under the GNU Lesser General Public License on
Github.com and can be downloaded at
https://github.com/eitchnet/ch.eitchnet.privilege
The main developer is Robert von Burg <eitch@eitchnet.ch> who also maintains the
Github repository. He is available for all questions regarding Privilege
Motivation
=======================================================================
In some cases a developer might want to restrict access to an application
depending on the role which an authenticated user has. In other cases the
developer would need a more finely grained control by restricting access to a
certain object, or a certain method call.
We were looking for an API which would allows us to restrict access to a given
object in different ways. For instance it was our intention to not simply
restrict access to a specific object type, or instance, but to restrict access
to an instance of the object if it had fields set to a specific value.
Evaluations on existing libraries which implement access restriction did not
provide an API which suited our needs or which were not easily implemented, thus
leading to the design of Privilege.
Design Goals
=======================================================================
When a developer needs to implement access restriction an application there are
different questions which the developer will ask:
- Does the user have a specific role?
- Does the user have a specific privilege i.e. is the user allowed to perform a
specific action?
- Is a user allowed to access a specific type of object?
- Is a user allowed to access a specific instance of a type?
- Is a user allowed to access a field on a specific object?
Privilege's design goals are to allow the developer to answer these questions
with an API which does not mean implementing a lot of additional project
specific code.
Further in Privilege it should be possible to perform the normal CRUD functions:
- Create users, roles, privileges, etc.
- Read existing users, roles, privileges, etc.
- Update users, roles, privileges, etc.
- Delete users, roles, privileges, etc.
It should be possible to store Privilege's data in different databases,
depending on the application. For example it should be able to store the data in
XML files, in a LDAP directory and so forth.
Documentation
=======================================================================
The current documentation, though a bit outdated, can be found in the docs/
directory of the Repository
Compiling
=======================================================================
Privilege is a Maven3 project and can be built by simply performing the
following command:
$ mvn compile
Using
=======================================================================
To use Privilege see the ch.eitchnet.privilege.test.PrivilegeTest.java class
which contains a few test cases including showing how to load Privilege.
This documentation is still in need of more work, but for any questions please
don't hesitate to write an e-mail to the developer and we'll find a solution.
Switzerland, the 29. July 2012
Robert von Burg

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<Privilege>
<Container>
<Parameters>
<!-- parameters for the container itself -->
<Parameter name="secretKey" value="5185F447-6317-4856-B40E-573919BA0A16" />
<Parameter name="secretSalt" value="00F6E88C-A64F-410A-8FCF-9CD340E340F7" />
<Parameter name="persistSessions" value="true" />
<Parameter name="persistSessionsPath" value="./target/${target}/sessions.dat" />
<Parameter name="autoPersistOnUserChangesData" value="true" />
<Parameter name="privilegeConflictResolution" value="STRICT" />
</Parameters>
<EncryptionHandler class="ch.eitchnet.privilege.handler.DefaultEncryptionHandler">
<Parameters>
<Parameter name="hashAlgorithm" value="SHA-256" />
</Parameters>
</EncryptionHandler>
<PersistenceHandler class="ch.eitchnet.privilege.handler.XmlPersistenceHandler">
<Parameters>
<Parameter name="basePath" value="./target/${target}" />
<Parameter name="usersXmlFile" value="PrivilegeUsers.xml" />
<Parameter name="rolesXmlFile" value="PrivilegeRoles.xml" />
</Parameters>
</PersistenceHandler>
</Container>
<Policies>
<Policy name="DefaultPrivilege" class="ch.eitchnet.privilege.policy.DefaultPrivilege" />
<Policy name="RoleAccessPrivilege" class="ch.eitchnet.privilege.policy.RoleAccessPrivilege" />
<Policy name="UserAccessPrivilege" class="ch.eitchnet.privilege.policy.UserAccessPrivilege" />
</Policies>
</Privilege>

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<Privilege>
<Container>
<Parameters>
<!-- parameters for the container itself -->
<Parameter name="autoPersistOnUserChangesData" value="true" />
<Parameter name="privilegeConflictResolution" value="MERGE" />
</Parameters>
<EncryptionHandler class="ch.eitchnet.privilege.handler.DefaultEncryptionHandler">
<Parameters>
<Parameter name="hashAlgorithm" value="SHA-256" />
</Parameters>
</EncryptionHandler>
<PersistenceHandler class="ch.eitchnet.privilege.handler.XmlPersistenceHandler">
<Parameters>
<Parameter name="basePath" value="./target/${target}" />
<Parameter name="usersXmlFile" value="PrivilegeUsersMerge.xml" />
<Parameter name="rolesXmlFile" value="PrivilegeRolesMerge.xml" />
</Parameters>
</PersistenceHandler>
</Container>
<Policies>
<Policy name="DefaultPrivilege" class="ch.eitchnet.privilege.policy.DefaultPrivilege" />
<Policy name="RoleAccessPrivilege" class="ch.eitchnet.privilege.policy.RoleAccessPrivilege" />
<Policy name="UserAccessPrivilege" class="ch.eitchnet.privilege.policy.UserAccessPrivilege" />
</Policies>
</Privilege>

View File

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8"?>
<Roles>
<Role name="PrivilegeAdmin">
<Privilege name="PrivilegeAction" policy="DefaultPrivilege">
<Allow>Persist</Allow>
<Allow>Reload</Allow>
<Allow>GetPolicies</Allow>
</Privilege>
<Privilege name="PrivilegeGetRole" policy="RoleAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeAddRole" policy="RoleAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeRemoveRole" policy="RoleAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeModifyRole" policy="RoleAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeGetUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeAddUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeRemoveUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeModifyUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeAddRoleToUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeRemoveRoleFromUser" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeSetUserLocale" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
<Privilege name="PrivilegeSetUserState" policy="UserAccessPrivilege">
<Allow>ENABLED</Allow>
<Allow>DISABLED</Allow>
<Deny>SYSTEM</Deny>
</Privilege>
<Privilege name="PrivilegeSetUserPassword" policy="UserAccessPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
</Role>
<Role name="AppUser">
<Privilege name="ch.eitchnet.privilege.test.model.TestRestrictable" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
</Role>
<Role name="MyRole">
<Privilege name="Foo" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
</Role>
<Role name="MyRole2">
<Privilege name="Foo" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
</Role>
<Role name="system_admin_privileges">
<Privilege name="ch.eitchnet.privilege.handler.SystemUserAction" policy="DefaultPrivilege">
<Allow>ch.eitchnet.privilege.test.model.TestSystemUserAction</Allow>
<Deny>ch.eitchnet.privilege.test.model.TestSystemUserActionDeny</Deny>
</Privilege>
<Privilege name="ch.eitchnet.privilege.test.model.TestSystemRestrictable" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
</Role>
<Role name="restrictedRole">
<Privilege name="ch.eitchnet.privilege.handler.SystemUserAction" policy="DefaultPrivilege">
<Allow>hello</Allow>
<Deny>goodbye</Deny>
</Privilege>
</Role>
</Roles>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<Roles>
<Role name="RoleA1">
<Privilege name="Foo" policy="DefaultPrivilege">
<Allow>allow1</Allow>
</Privilege>
</Role>
<Role name="RoleA2">
<Privilege name="Foo" policy="DefaultPrivilege">
<AllAllowed>true</AllAllowed>
</Privilege>
</Role>
<Role name="RoleB1">
<Privilege name="Bar" policy="DefaultPrivilege">
<Allow>allow1</Allow>
<Deny>deny1</Deny>
</Privilege>
</Role>
<Role name="RoleB2">
<Privilege name="Bar" policy="DefaultPrivilege">
<Allow>allow2</Allow>
<Deny>deny2</Deny>
</Privilege>
</Role>
</Roles>

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<Users>
<User userId="1" username="admin" password="8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918">
<Firstname>Application</Firstname>
<Lastname>Administrator</Lastname>
<State>ENABLED</State>
<Locale>en_GB</Locale>
<Roles>
<Role>PrivilegeAdmin</Role>
<Role>AppUser</Role>
</Roles>
<Properties>
<Property name="organization" value="eitchnet.ch" />
<Property name="organizationalUnit" value="Development" />
</Properties>
</User>
<User userId="2" username="system_admin">
<Firstname>System User</Firstname>
<Lastname>Administrator</Lastname>
<State>SYSTEM</State>
<Locale>en_GB</Locale>
<Roles>
<Role>system_admin_privileges</Role>
</Roles>
</User>
<User userId="3" username="system_admin2">
<Firstname>System User</Firstname>
<Lastname>Administrator</Lastname>
<State>SYSTEM</State>
<Locale>en_GB</Locale>
<Roles>
<Role>system_admin_privileges</Role>
</Roles>
</User>
</Users>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<Users>
<User userId="1" username="userA" password="8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918">
<Firstname>System User</Firstname>
<Lastname>Administrator</Lastname>
<State>ENABLED</State>
<Locale>en_GB</Locale>
<Roles>
<Role>RoleA1</Role>
<Role>RoleA2</Role>
</Roles>
</User>
<User userId="2" username="userB" password="8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918">
<Firstname>System User</Firstname>
<Lastname>Administrator</Lastname>
<State>ENABLED</State>
<Locale>en_GB</Locale>
<Roles>
<Role>RoleB1</Role>
<Role>RoleB2</Role>
</Roles>
</User>
</Users>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,11 @@
A list of TODOs for Privilege
============================================
- Write up a proper explanation on the idea on how Privilege, PrivilegePolicy,
Restrictable and Roles fit together to grant privileges to Users
- i18n for any messages and exceptions!
- Finish the JavaDoc
- Set up a website =)

View File

@ -0,0 +1,70 @@
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ch.eitchnet</groupId>
<artifactId>ch.eitchnet.parent</artifactId>
<version>1.1.0-SNAPSHOT</version>
<relativePath>../ch.eitchnet.parent/pom.xml</relativePath>
</parent>
<artifactId>ch.eitchnet.privilege</artifactId>
<packaging>jar</packaging>
<name>ch.eitchnet.privilege</name>
<url>https://github.com/eitchnet/ch.eitchnet.privilege</url>
<inceptionYear>2011</inceptionYear>
<properties>
<eitchnet.utils.version>1.1.0-SNAPSHOT</eitchnet.utils.version>
</properties>
<issueManagement>
<system>Github Issues</system>
<url>https://github.com/eitchnet/ch.eitchnet.privilege/issues</url>
</issueManagement>
<scm>
<connection>scm:git:https://github.com/eitchnet/ch.eitchnet.privilege.git</connection>
<developerConnection>scm:git:git@github.com:eitchnet/ch.eitchnet.privilege.git</developerConnection>
<url>https://github.com/eitchnet/ch.eitchnet.privilege</url>
<tag>HEAD</tag>
</scm>
<dependencies>
<dependency>
<groupId>ch.eitchnet</groupId>
<artifactId>ch.eitchnet.utils</artifactId>
<version>${eitchnet.utils.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-eclipse-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<jardesc>
<jar path="/home/eitch/privilege.jar"/>
<options buildIfNeeded="true" compress="true" descriptionLocation="/Privilege/privilege.jardesc" exportErrors="true" exportWarnings="true" includeDirectoryEntries="false" overwrite="false" saveDescription="false" storeRefactorings="false" useSourceFolders="false"/>
<storedRefactorings deprecationInfo="true" structuralOnly="false"/>
<selectedProjects/>
<manifest generateManifest="false" manifestLocation="/Privilege/MANIFEST.MF" manifestVersion="1.0" reuseManifest="false" saveManifest="true" usesManifest="true">
<sealing sealJar="false">
<packagesToSeal/>
<packagesToUnSeal/>
</sealing>
</manifest>
<selectedElements exportClassFiles="true" exportJavaFiles="true" exportOutputFolder="false">
<javaElement handleIdentifier="=Privilege/src"/>
<file path="/Privilege/.classpath"/>
<file path="/Privilege/.project"/>
</selectedElements>
</jardesc>

View File

@ -0,0 +1,34 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.base;
/**
* Exception thrown if access is denied during login, or if a certain privilege is not granted
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class AccessDeniedException extends PrivilegeException {
private static final long serialVersionUID = 1L;
/**
* @param msg
* detail on why and where access was denied
*/
public AccessDeniedException(String msg) {
super(msg);
}
}

View File

@ -0,0 +1,19 @@
package ch.eitchnet.privilege.base;
/**
* Exception thrown if the given credentials are invalid
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class InvalidCredentialsException extends AccessDeniedException {
private static final long serialVersionUID = 1L;
/**
* @param msg
* the message to accompany the exception
*/
public InvalidCredentialsException(String msg) {
super(msg);
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.base;
import ch.eitchnet.privilege.model.internal.Role;
import ch.eitchnet.privilege.model.internal.User;
/**
* The {@link PrivilegeConflictResolution} defines what should be done if a {@link User} has {@link Role Roles} which
* have Privileges with conflicting names.
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public enum PrivilegeConflictResolution {
/**
* STRICT requires that a User may not have conflicting Privileges throug multiple Roles. In this case an Exception
* is thrown.
*/
STRICT {
@Override
public boolean isStrict() {
return true;
}
},
/**
* MERGE defines that if conflicting privileges are encountered then a merge is to take place. A merge means that if
* all is allowed, then that wins. Otherwise any existing allow and deny lists are merged
*/
MERGE {
@Override
public boolean isStrict() {
return false;
}
};
public abstract boolean isStrict();
}

View File

@ -0,0 +1,48 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.base;
/**
* Main {@link RuntimeException} thrown if something goes wrong in Privilege
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class PrivilegeException extends RuntimeException {
private static final long serialVersionUID = 1L;
/**
* Default constructor
*
* @param string
* message to go with the exception
*/
public PrivilegeException(String string) {
super(string);
}
/**
* Constructor with underlying exception
*
* @param string
* message to go with the exception
* @param t
* throwable to wrap with this exception which is the underlying exception of this exception
*/
public PrivilegeException(String string, Throwable t) {
super(string, t);
}
}

View File

@ -0,0 +1,119 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.handler;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.text.MessageFormat;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.eitchnet.privilege.base.PrivilegeException;
import ch.eitchnet.privilege.helper.XmlConstants;
import ch.eitchnet.utils.helper.StringHelper;
/**
* <p>
* This default {@link EncryptionHandler} creates tokens using a {@link SecureRandom} object. Hashing is done by using
* {@link MessageDigest} and the configured algorithm which is passed in the parameters
* </p>
*
* Required parameters:
* <ul>
* <li> {@link XmlConstants#XML_PARAM_HASH_ALGORITHM}</li>
* </ul>
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class DefaultEncryptionHandler implements EncryptionHandler {
/**
* The log4j logger used in this instance
*/
private static final Logger logger = LoggerFactory.getLogger(DefaultEncryptionHandler.class);
/**
* The {@link SecureRandom} which is used to create new tokens
*/
private SecureRandom secureRandom;
/**
* The configured hash algorithm for this instance
*/
private String hashAlgorithm;
@Override
public String convertToHash(String string) {
return convertToHash(string.getBytes());
}
@Override
public String convertToHash(byte[] bytes) {
try {
return StringHelper.hashAsHex(this.hashAlgorithm, bytes);
} catch (RuntimeException e) {
if (e.getCause() == null)
throw e;
if (e.getCause().getClass().equals(NoSuchAlgorithmException.class))
throw new PrivilegeException(
MessageFormat.format("Algorithm {0} was not found!", this.hashAlgorithm), e.getCause()); //$NON-NLS-1$
if (e.getCause().getClass().equals(UnsupportedEncodingException.class))
throw new PrivilegeException("Charset ASCII is not supported!", e.getCause()); //$NON-NLS-1$
throw e;
}
}
@Override
public String nextToken() {
byte[] bytes = new byte[16];
this.secureRandom.nextBytes(bytes);
String randomString = new String(bytes);
return randomString;
}
@Override
public void initialize(Map<String, String> parameterMap) {
this.secureRandom = new SecureRandom();
// get hash algorithm parameters
this.hashAlgorithm = parameterMap.get(XmlConstants.XML_PARAM_HASH_ALGORITHM);
if (this.hashAlgorithm == null || this.hashAlgorithm.isEmpty()) {
String msg = "[{0}] Defined parameter {1} is invalid"; //$NON-NLS-1$
msg = MessageFormat.format(msg, EncryptionHandler.class.getName(), XmlConstants.XML_PARAM_HASH_ALGORITHM);
throw new PrivilegeException(msg);
}
// test hash algorithm
try {
convertToHash("test"); //$NON-NLS-1$
DefaultEncryptionHandler.logger.info(MessageFormat
.format("Using hashing algorithm {0}", this.hashAlgorithm)); //$NON-NLS-1$
} catch (Exception e) {
String msg = "[{0}] Defined parameter {1} is invalid because of underlying exception: {2}"; //$NON-NLS-1$
msg = MessageFormat.format(msg, EncryptionHandler.class.getName(), XmlConstants.XML_PARAM_HASH_ALGORITHM,
e.getLocalizedMessage());
throw new PrivilegeException(msg, e);
}
}
}

View File

@ -0,0 +1,61 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.handler;
import java.util.Map;
/**
* The {@link EncryptionHandler} exposes API which is used to handle encrypting of strings, or returning secure tokens
* for certificates and so forth
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public interface EncryptionHandler {
/**
* Calculates or generates a token which can be used to identify certificates and so forth
*
* @return the secure token
*/
public String nextToken();
/**
* Converts a given string, e.g. a password to a hash which is defined by the concrete implementation
*
* @param string
* the string to convert
* @return the hash of the string after converting
*/
public String convertToHash(String string);
/**
* Converts a given byte array, e.g. a password to a hash which is defined by the concrete implementation
*
* @param bytes
* the bytes to convert
* @return the hash of the string after converting
*/
public String convertToHash(byte[] bytes);
/**
* Initialize the concrete {@link EncryptionHandler}. The passed parameter map contains any configuration the
* concrete {@link EncryptionHandler} might need
*
* @param parameterMap
* a map containing configuration properties
*/
public void initialize(Map<String, String> parameterMap);
}

View File

@ -0,0 +1,151 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.handler;
import java.util.List;
import java.util.Map;
import ch.eitchnet.privilege.model.IPrivilege;
import ch.eitchnet.privilege.model.Restrictable;
import ch.eitchnet.privilege.model.internal.Role;
import ch.eitchnet.privilege.model.internal.User;
import ch.eitchnet.privilege.policy.PrivilegePolicy;
/**
* <p>
* The {@link PersistenceHandler} takes care of retrieving and persisting model objects to the underlying database. This
* database can be simple XML files, or an LDAP and so forth
* </p>
*
* <p>
* The {@link PersistenceHandler} also serves the special {@link PrivilegePolicy} objects. These policies are special
* objects which implement an algorithm to define if an action is allowed on a {@link Restrictable} by a {@link Role}
* and {@link IPrivilege}
* </p>
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public interface PersistenceHandler {
/**
* Returns all currently known {@link User}s
*
* @return all currently known {@link User}s
*/
public List<User> getAllUsers();
/**
* Returns all currently known {@link Role}s
*
* @return all currently known {@link Role}s
*/
public List<Role> getAllRoles();
/**
* Returns a {@link User} object from the underlying database
*
* @param username
* the name/id of the {@link User} object to return
*
* @return the {@link User} object, or null if it was not found
*/
public User getUser(String username);
/**
* Returns a {@link Role} object from the underlying database
*
* @param roleName
* the name/id of the {@link Role} object to return
*
* @return the {@link Role} object, or null if it was not found
*/
public Role getRole(String roleName);
/**
* Removes a {@link User} with the given name and returns the removed object if it existed
*
* @param username
* the name of the {@link User} to remove
*
* @return the {@link User} removed, or null if it did not exist
*/
public User removeUser(String username);
/**
* Removes a {@link Role} with the given name and returns the removed object if it existed
*
* @param roleName
* the name of the {@link Role} to remove
*
* @return the {@link Role} removed, or null if it did not exist
*/
public Role removeRole(String roleName);
/**
* Adds a {@link User} object to the underlying database
*
* @param user
* the {@link User} object to add
*/
public void addUser(User user);
/**
* Replaces the existing {@link User} object in the underlying database
*
* @param user
* the {@link User} object to add
*/
public void replaceUser(User user);
/**
* Adds a {@link Role} object to the underlying database
*
* @param role
* the {@link User} object to add
*/
public void addRole(Role role);
/**
* Replaces the {@link Role} object in the underlying database
*
* @param role
* the {@link User} object to add
*/
public void replaceRole(Role role);
/**
* Informs this {@link PersistenceHandler} to persist any changes which need to be saved
*
* @return true if changes were persisted successfully, false if nothing needed to be persisted
*/
public boolean persist();
/**
* Informs this {@link PersistenceHandler} to reload the data from the backend
*
* @return true if the reload was successful, false if something went wrong
*/
public boolean reload();
/**
* Initialize the concrete {@link PersistenceHandler}. The passed parameter map contains any configuration the
* concrete {@link PersistenceHandler} might need
*
* @param parameterMap
* a map containing configuration properties
*/
public void initialize(Map<String, String> parameterMap);
}

View File

@ -0,0 +1,689 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.handler;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import ch.eitchnet.privilege.base.AccessDeniedException;
import ch.eitchnet.privilege.base.PrivilegeConflictResolution;
import ch.eitchnet.privilege.base.PrivilegeException;
import ch.eitchnet.privilege.model.Certificate;
import ch.eitchnet.privilege.model.IPrivilege;
import ch.eitchnet.privilege.model.PrivilegeContext;
import ch.eitchnet.privilege.model.PrivilegeRep;
import ch.eitchnet.privilege.model.RoleRep;
import ch.eitchnet.privilege.model.UserRep;
import ch.eitchnet.privilege.model.UserState;
import ch.eitchnet.privilege.model.internal.Role;
import ch.eitchnet.privilege.model.internal.User;
import ch.eitchnet.privilege.policy.PrivilegePolicy;
/**
* The {@link PrivilegeHandler} is the centrally exposed API for accessing the privilege library. It exposes all needed
* methods to access Privilege data model objects, modify them and validate if users or roles have privileges to perform
* an action
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public interface PrivilegeHandler {
///
/**
* Privilege "PrivilegeAction" which is used for privileges which are not further categorized e.g. s
* {@link #PRIVILEGE_ACTION_PERSIST} and {@link #PRIVILEGE_ACTION_GET_POLICIES}
*/
public static final String PRIVILEGE_ACTION = "PrivilegeAction";
/**
* For Privilege "PrivilegeAction" value required to be able to persist changes if not exempted by auto persist or
* <code>allAllowed</code>
*/
public static final String PRIVILEGE_ACTION_PERSIST = "Persist";
/**
* For Privilege "PrivilegeAction" value required to be able to persist session if not exempted by
* <code>allAllowed</code>
*/
public static final String PRIVILEGE_ACTION_PERSIST_SESSIONS = "PersistSessions";
/**
* For Privilege "PrivilegeAction" value required to be able to reload changes if not exempted by
* <code>allAllowed</code>
*/
public static final String PRIVILEGE_ACTION_RELOAD = "Reload";
/**
* For Privilege "PrivilegeAction" value required to get currently configured policies if not
* <code>allAllowed</code>
*/
public static final String PRIVILEGE_ACTION_GET_POLICIES = "GetPolicies";
/**
* For Privilege "PrivilegeAction" value required to get a certificate if not <code>allAllowed</code>
*/
public static final String PRIVILEGE_ACTION_GET_CERTIFICATE = "GetCertificate";
/**
* For Privilege "PrivilegeAction" value required to get all certificates if not <code>allAllowed</code>
*/
public static final String PRIVILEGE_ACTION_GET_CERTIFICATES = "GetCertificates";
///
/**
* Privilege "PrivilegeGetRole" which is used to validate that a user can get a specific role
*/
public static final String PRIVILEGE_GET_ROLE = "PrivilegeGetRole";
/**
* Privilege "PrivilegeAddRole" which is used to validate that a user can add a specific role
*/
public static final String PRIVILEGE_ADD_ROLE = "PrivilegeAddRole";
/**
* Privilege "PrivilegeRemoveRole" which is used to validate that a user can remove a specific role
*/
public static final String PRIVILEGE_REMOVE_ROLE = "PrivilegeRemoveRole";
/**
* Privilege "PrivilegeModifyRole" which is used to validate that a user can modify a specific role. <b>Note:</b>
* This includes modifying of the privileges on the role
*/
public static final String PRIVILEGE_MODIFY_ROLE = "PrivilegeModifyRole";
///
/**
* Privilege "PrivilegeGetUser" which is used to validate that a user can get a specific user
*/
public static final String PRIVILEGE_GET_USER = "PrivilegeGetUser";
/**
* Privilege "PrivilegeAddUser" which is used to validate that a user can add a specific user
*/
public static final String PRIVILEGE_ADD_USER = "PrivilegeAddUser";
/**
* Privilege "PrivilegeRemoveUser" which is used to validate that a user can remove a specific user
*/
public static final String PRIVILEGE_REMOVE_USER = "PrivilegeRemoveUser";
/**
* Privilege "PrivilegeModifyUser" which is used to validate that a user can modify a specific user
*/
public static final String PRIVILEGE_MODIFY_USER = "PrivilegeModifyUser";
/**
* Privilege "PrivilegeAddRoleToUser" which is used to validate that a user can add a specific role to a specific
* user
*/
public static final String PRIVILEGE_ADD_ROLE_TO_USER = "PrivilegeAddRoleToUser";
/**
* Privilege "PrivilegeRemoveRoleFromUser" which is used to validate that a user can remove a specific role from a
* specific user
*/
public static final String PRIVILEGE_REMOVE_ROLE_FROM_USER = "PrivilegeRemoveRoleFromUser";
/**
* Privilege "PRIVILEGE_SET_USER_LOCALE" which is used to validate that a user can set the locale of a user, or
* their own
*/
public static final String PRIVILEGE_SET_USER_LOCALE = "PrivilegeSetUserLocale";
/**
* Privilege "PRIVILEGE_SET_USER_STATE" which is used to validate that a user can set the state of a user
*/
public static final String PRIVILEGE_SET_USER_STATE = "PrivilegeSetUserState";
/**
* Privilege "PRIVILEGE_SET_USER_PASSWORD" which is used to validate that a user can set the password of a user, or
* their own
*/
public static final String PRIVILEGE_SET_USER_PASSWORD = "PrivilegeSetUserPassword";
///
/**
* configuration parameter to define a secret_key
*/
public static final String PARAM_SECRET_KEY = "secretKey"; //$NON-NLS-1$
/**
* configuration parameter to define a secret salt
*/
public static final String PARAM_SECRET_SALT = "secretSalt"; //$NON-NLS-1$
/**
* configuration parameter to define automatic persisting on password change
*/
public static final String PARAM_AUTO_PERSIST_ON_USER_CHANGES_DATA = "autoPersistOnUserChangesData"; //$NON-NLS-1$
/**
* configuration parameter to define if sessions should be persisted
*/
public static final String PARAM_PERSIST_SESSIONS = "persistSessions"; //$NON-NLS-1$
/**
* configuration parameter to define where sessions are to be persisted
*/
public static final String PARAM_PERSIST_SESSIONS_PATH = "persistSessionsPath"; //$NON-NLS-1$
/**
* configuration parameter to define {@link PrivilegeConflictResolution}
*/
public static final String PARAM_PRIVILEGE_CONFLICT_RESOLUTION = "privilegeConflictResolution";
/**
* Returns a {@link UserRep} for the given username
*
* @param certificate
* the {@link Certificate} of the user which has the privilege to perform this action
* @param username
* the name of the {@link UserRep} to return
*
* @return the {@link UserRep} for the given username, or null if it was not found
*/
public UserRep getUser(Certificate certificate, String username);
/**
* Returns a {@link RoleRep} for the given roleName
*
* @param certificate
* the {@link Certificate} of the user which has the privilege to perform this action
* @param roleName
* the name of the {@link RoleRep} to return
*
* @return the {@link RoleRep} for the given roleName, or null if it was not found
*/
public RoleRep getRole(Certificate certificate, String roleName);
/**
* Returns the map of {@link PrivilegePolicy} definitions
*
* @param certificate
* the {@link Certificate} of the user which has the privilege to perform this action
*
* @return the map of {@link PrivilegePolicy} definitions
*/
public Map<String, String> getPolicyDefs(Certificate certificate);
/**
* Returns the list of {@link Certificate Certificates}
*
* @param certificate
* the {@link Certificate} of the user which has the privilege to perform this action
*
* @return the list of {@link Certificate Certificates}
*/
public List<Certificate> getCertificates(Certificate certificate);
/**
* Returns all {@link RoleRep RoleReps}
*
* @param certificate
* the {@link Certificate} of the user which has the privilege to perform this action
*
* @return the list of {@link RoleRep RoleReps}
*/
public List<RoleRep> getRoles(Certificate certificate);
/**
* Returns all {@link UserRep UserReps}
*
* @param certificate
* the {@link Certificate} of the user which has the privilege to perform this action
*
* @return the list of {@link UserRep UserReps}
*/
public List<UserRep> getUsers(Certificate certificate);
/**
* Method to query {@link UserRep} which meet the criteria set in the given {@link UserRep}. Null fields mean the
* fields are irrelevant.
*
* @param certificate
* the {@link Certificate} of the user which has the privilege to perform this action
* @param selectorRep
* the {@link UserRep} to use as criteria selection
*
* @return a list of {@link UserRep}s which fit the given criteria
*/
public List<UserRep> queryUsers(Certificate certificate, UserRep selectorRep);
/**
* Removes the user with the given username
*
* @param certificate
* the {@link Certificate} of the user which has the privilege to perform this action
* @param username
* the username of the user to remove
*
* @return the {@link UserRep} of the user removed, or null if the user did not exist
*
* @throws AccessDeniedException
* if the user for this certificate may not perform the action
* @throws PrivilegeException
* if there is anything wrong with this certificate
*/
public UserRep removeUser(Certificate certificate, String username)
throws AccessDeniedException, PrivilegeException;
/**
* Removes the role with the given roleName from the user with the given username
*
* @param certificate
* the {@link Certificate} of the user which has the privilege to perform this action
* @param username
* the username of the user from which the role is to be removed
* @param roleName
* the roleName of the role to remove from the user
*
* @throws AccessDeniedException
* if the user for this certificate may not perform the action
* @throws PrivilegeException
* if there is anything wrong with this certificate
*/
public UserRep removeRoleFromUser(Certificate certificate, String username, String roleName)
throws AccessDeniedException, PrivilegeException;
/**
* Removes the role with the given roleName
*
* @param certificate
* the {@link Certificate} of the user which has the privilege to perform this action
* @param roleName
* the roleName of the role to remove
*
* @return the {@link RoleRep} of the role removed, or null if the role did not exist
*
* @throws AccessDeniedException
* if the user for this certificate may not perform the action
* @throws PrivilegeException
* if there is anything wrong with this certificate or the role is still in use by a user
*/
public RoleRep removeRole(Certificate certificate, String roleName)
throws AccessDeniedException, PrivilegeException;
/**
* Removes the privilege with the given privilegeName from the role with the given roleName
*
* @param certificate
* the {@link Certificate} of the user which has the privilege to perform this action
* @param roleName
* the roleName of the role from which the privilege is to be removed
* @param privilegeName
* the privilegeName of the privilege to remove from the role
*
* @throws AccessDeniedException
* if the user for this certificate may not perform the action
* @throws PrivilegeException
* if there is anything wrong with this certificate
*/
public RoleRep removePrivilegeFromRole(Certificate certificate, String roleName, String privilegeName)
throws AccessDeniedException, PrivilegeException;
/**
* <p>
* Adds a new user with the information from this {@link UserRep}
* </p>
*
* <p>
* If the password given is null, then the user is created, but can not not login! Otherwise the password must meet
* the requirements of the implementation under {@link PrivilegeHandler#validatePassword(byte[])}
* </p>
*
* @param certificate
* the {@link Certificate} of the user which has the privilege to perform this action
* @param userRep
* the {@link UserRep} containing the information to create the new {@link User}
* @param password
* the password of the new user. If the password is null, then this is accepted but the user can not
* login, otherwise the password must be validated against
* {@link PrivilegeHandler#validatePassword(byte[])}
*
* @throws AccessDeniedException
* if the user for this certificate may not perform the action
* @throws PrivilegeException
* if there is anything wrong with this certificate or the user already exists
*/
public UserRep addUser(Certificate certificate, UserRep userRep, byte[] password)
throws AccessDeniedException, PrivilegeException;
/**
* <p>
* Updates the fields for the user with the given user. All fields on the given {@link UserRep} which are non-null
* will be updated on the existing user. The username on the given {@link UserRep} must be set and correspond to an
* existing user.
* </p>
*
* The following fields are considered updateable:
* <ul>
* <li>{@link UserRep#getFirstname()}</li>
* <li>{@link UserRep#getLastname()}</li>
* <li>{@link UserRep#getLocale()}</li>
* <li>{@link UserRep#getProperties()} - the existing properties will be replaced with the given properties</li>
* </ul>
*
* <p>
* Any other fields will be ignored
* </p>
*
* @param certificate
* the {@link Certificate} of the user which has the privilege to perform this action
* @param userRep
* the {@link UserRep} with the fields set to their new values
*
* @throws AccessDeniedException
* if the user for this certificate may not perform the action
* @throws PrivilegeException
* if there is anything wrong with this certificate or if the user does not exist
*/
public UserRep updateUser(Certificate certificate, UserRep userRep)
throws AccessDeniedException, PrivilegeException;
/**
* <p>
* Replaces the existing user with the information from this {@link UserRep} if the user already exists
* </p>
*
* <p>
* If the password given is null, then the user is created, but can not not login! Otherwise the password must meet
* the requirements of the implementation under {@link PrivilegeHandler#validatePassword(byte[])}
* </p>
*
* @param certificate
* the {@link Certificate} of the user which has the privilege to perform this action
* @param userRep
* the {@link UserRep} containing the information to replace the existing {@link User}
* @param password
* the password of the new user. If the password is null, then this is accepted but the user can not
* login, otherwise the password must be validated against
* {@link PrivilegeHandler#validatePassword(byte[])}
*
* @throws AccessDeniedException
* if the user for this certificate may not perform the action
* @throws PrivilegeException
* if there is anything wrong with this certificate or if the user does not exist
*/
public UserRep replaceUser(Certificate certificate, UserRep userRep, byte[] password)
throws AccessDeniedException, PrivilegeException;
/**
* Adds a new role with the information from this {@link RoleRep}
*
* @param certificate
* the {@link Certificate} of the user which has the privilege to perform this action
* @param roleRep
* the {@link RoleRep} containing the information to create the new {@link Role}
*
* @throws AccessDeniedException
* if the user for this certificate may not perform the action
* @throws PrivilegeException
* if there is anything wrong with this certificate or if the role already exists
*/
public RoleRep addRole(Certificate certificate, RoleRep roleRep) throws AccessDeniedException, PrivilegeException;
/**
* Replaces the existing role with the information from this {@link RoleRep}
*
* @param certificate
* the {@link Certificate} of the user which has the privilege to perform this action
* @param roleRep
* the {@link RoleRep} containing the information to replace the existing {@link Role}
*
* @throws AccessDeniedException
* if the user for this certificate may not perform the action
* @throws PrivilegeException
* if there is anything wrong with this certificate or if the role does not exist
*/
public RoleRep replaceRole(Certificate certificate, RoleRep roleRep)
throws AccessDeniedException, PrivilegeException;
/**
* Adds the role with the given roleName to the {@link User} with the given username
*
* @param certificate
* the {@link Certificate} of the user which has the privilege to perform this action
* @param username
* the username of the {@link User} to which the role should be added
* @param roleName
* the roleName of the {@link Role} which should be added to the {@link User}
*
* @throws AccessDeniedException
* if the user for this certificate may not perform the action
* @throws PrivilegeException
* if there is anything wrong with this certificate or if the role does not exist
*/
public UserRep addRoleToUser(Certificate certificate, String username, String roleName)
throws AccessDeniedException, PrivilegeException;
/**
* Adds the {@link PrivilegeRep} to the {@link Role} with the given roleName or replaces it, if it already exists
*
* @param certificate
* the {@link Certificate} of the user which has the privilege to perform this action
* @param roleName
* the roleName of the {@link Role} to which the privilege should be added
* @param privilegeRep
* the representation of the {@link IPrivilege} which should be added or replaced on the {@link Role}
*
* @throws AccessDeniedException
* if the user for this certificate may not perform the action
* @throws PrivilegeException
* if there is anything wrong with this certificate or the role does not exist
*/
public RoleRep addOrReplacePrivilegeOnRole(Certificate certificate, String roleName, PrivilegeRep privilegeRep)
throws AccessDeniedException, PrivilegeException;
/**
* <p>
* Changes the password for the {@link User} with the given username. If the password is null, then the {@link User}
* can not login anymore. Otherwise the password must meet the requirements of the implementation under
* {@link PrivilegeHandler#validatePassword(byte[])}
* </p>
*
* <p>
* It should be possible for a user to change their own password
* </p>
*
* @param certificate
* the {@link Certificate} of the user which has the privilege to perform this action
* @param username
* the username of the {@link User} for which the password is to be changed
* @param password
* the new password for this user. If the password is null, then the {@link User} can not login anymore.
* Otherwise the password must meet the requirements of the implementation under
* {@link PrivilegeHandler#validatePassword(byte[])}
*
* @throws AccessDeniedException
* if the user for this certificate may not perform the action
* @throws PrivilegeException
* if there is anything wrong with this certificate
*/
public void setUserPassword(Certificate certificate, String username, byte[] password)
throws AccessDeniedException, PrivilegeException;
/**
* Changes the {@link UserState} of the user
*
* @param certificate
* the {@link Certificate} of the user which has the privilege to perform this action
* @param username
* the username of the {@link User} for which the {@link UserState} is to be changed
* @param state
* the new state for the user
*
* @throws AccessDeniedException
* if the user for this certificate may not perform the action
* @throws PrivilegeException
* if there is anything wrong with this certificate
*/
public UserRep setUserState(Certificate certificate, String username, UserState state)
throws AccessDeniedException, PrivilegeException;
/**
* Changes the {@link Locale} of the user
*
* @param certificate
* the {@link Certificate} of the user which has the privilege to perform this action
* @param username
* the username of the {@link User} for which the {@link Locale} is to be changed
* @param locale
* the new {@link Locale} for the user
*
* @throws AccessDeniedException
* if the user for this certificate may not perform the action
* @throws PrivilegeException
* if there is anything wrong with this certificate
*/
public UserRep setUserLocale(Certificate certificate, String username, Locale locale)
throws AccessDeniedException, PrivilegeException;
/**
* Authenticates a user by validating that a {@link User} for the given username and password exist and then returns
* a {@link Certificate} with which this user may then perform actions
*
* @param username
* the username of the {@link User} which is registered in the {@link PersistenceHandler}
* @param password
* the password with which this user is to be authenticated. Null passwords are not accepted and they
* must meet the requirements of the {@link #validatePassword(byte[])}-method
*
* @return a {@link Certificate} with which this user may then perform actions
*
* @throws AccessDeniedException
* if the user credentials are not valid
*/
public Certificate authenticate(String username, byte[] password) throws AccessDeniedException;
/**
* Invalidates the session for the given {@link Certificate}, effectively logging out the user who was authenticated
* with the credentials associated to the given {@link Certificate}
*
* @param certificate
* the {@link Certificate} for which the session is to be invalidated
* @return true if the session was still valid and is now invalidated, false otherwise
*/
public boolean invalidateSession(Certificate certificate);
/**
* Checks if the given {@link Certificate} is valid. This means that the certificate is for a valid session and that
* the user exists for the certificate. This method checks if the {@link Certificate} has been tampered with
*
* @param certificate
* the {@link Certificate} to check
*
* @throws PrivilegeException
* if there is anything wrong with this certificate
*/
public void isCertificateValid(Certificate certificate) throws PrivilegeException;
/**
* Checks that the given password belongs to the given {@link Certificate}. If it doesn't, then a
* {@link PrivilegeException} is thrown
*
* @param certificate
* the certificate for which to check the password
* @param password
* the password to check against the user from the certificate
*
* @throws PrivilegeException
* if the certificate is invalid or the password does not match
*/
public void checkPassword(Certificate certificate, byte[] password) throws PrivilegeException;
/**
* Returns the {@link PrivilegeContext} for the given {@link Certificate}. The {@link PrivilegeContext} is an
* encapsulated state of a user's privileges so that for the duration of a user's call, the user can perform their
* actions and do not need to access the {@link PrivilegeHandler} anymore
*
* @param certificate
* a valid {@link Certificate} for which a {@link PrivilegeContext} is to be returned
* @return the {@link PrivilegeContext} for the given {@link Certificate}
*
* @throws PrivilegeException
* if there is a configuration error or the {@link Certificate} is invalid
*/
public PrivilegeContext getPrivilegeContext(Certificate certificate) throws PrivilegeException;
/**
* Validate that the given password meets certain requirements. What these requirements are is a decision made by
* the concrete implementation
*
* @param password
* the password to be validated to meet certain requirements
*
* @throws PrivilegeException
* if the password does not implement the requirement of the concrete implementation
*/
public void validatePassword(byte[] password) throws PrivilegeException;
/**
* <p>
* Informs this {@link PersistenceHandler} to reload the data from the backend
* </p>
*
* <b>Note:</b> It depends on the underlying {@link PersistenceHandler} implementation if data really is read
*
* @param certificate
* the {@link Certificate} of the user which has the privilege to perform this action
*
* @return true if the reload was successful, false if something went wrong
*
* @throws AccessDeniedException
* if the users of the given certificate does not have the privilege to perform this action
*/
public boolean reload(Certificate certificate);
/**
* Persists any changes to the privilege data model. Changes are thus not persisted immediately, but must be
* actively performed
*
* @param certificate
* the {@link Certificate} of the user which has the privilege to perform this action
*
* @return true if changes were persisted, false if no changes were persisted
*
* @throws AccessDeniedException
* if the users of the given certificate does not have the privilege to perform this action
*/
public boolean persist(Certificate certificate) throws AccessDeniedException;
/**
* Persists all currently active sessions
*
* @param certificate
* the {@link Certificate} of the user which has the privilege to perform this action
*
* @return true if changes were persisted, false if not (i.e. not enabled)
*
* @throws AccessDeniedException
* if the users of the given certificate does not have the privilege to perform this action
*/
public boolean persistSessions(Certificate certificate) throws AccessDeniedException;
/**
* Special method to perform work as a System user, meaning the given systemUsername corresponds to an account which
* has the state {@link UserState#SYSTEM} and this user must have privilege to perform the concrete implementation
* of the given {@link SystemUserAction} instance
*
*
* @param systemUsername
* the username of the system user to perform the action as
* @param action
* the action to be performed as the system user
*
* @return the action
*
* @throws PrivilegeException
*/
public <T extends SystemUserAction> T runAsSystem(String systemUsername, T action) throws PrivilegeException;
/**
* Returns the {@link EncryptionHandler} instance
*
* @return the {@link EncryptionHandler} instance
*/
public EncryptionHandler getEncryptionHandler() throws PrivilegeException;
}

View File

@ -0,0 +1,52 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.handler;
import ch.eitchnet.privilege.model.Certificate;
import ch.eitchnet.privilege.model.PrivilegeContext;
import ch.eitchnet.privilege.model.Restrictable;
/**
* With this interface system actions, which are to be performed in an automated fashion, i.e. by cron jobs, can be
* implemented and then the authorized execution can be delegated to
* {@link PrivilegeHandler#runAsSystem(String, SystemUserAction)}
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public abstract class SystemUserAction implements Restrictable {
@Override
public String getPrivilegeName() {
return SystemUserAction.class.getName();
}
@Override
public Object getPrivilegeValue() {
return this.getClass().getName();
}
/**
* This method will be called by the {@link PrivilegeHandler} when an authorized {@link Certificate} has been
* generated to allow this action to properly validate its execution
*
* TODO: I'm not really happy with this... we might want to pass the certificate and then force the action to
* validate it to get the {@link PrivilegeContext} - we don't want the {@link PrivilegeContext} to live forever...
*
* @param privilegeContext
* the {@link PrivilegeContext} which was generated for a valid system user
*/
public abstract void execute(PrivilegeContext privilegeContext);
}

View File

@ -0,0 +1,314 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.handler;
import java.io.File;
import java.text.MessageFormat;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.eitchnet.privilege.base.PrivilegeException;
import ch.eitchnet.privilege.helper.XmlConstants;
import ch.eitchnet.privilege.model.internal.Role;
import ch.eitchnet.privilege.model.internal.User;
import ch.eitchnet.privilege.xml.PrivilegeRolesDomWriter;
import ch.eitchnet.privilege.xml.PrivilegeRolesSaxReader;
import ch.eitchnet.privilege.xml.PrivilegeUsersDomWriter;
import ch.eitchnet.privilege.xml.PrivilegeUsersSaxReader;
import ch.eitchnet.utils.helper.StringHelper;
import ch.eitchnet.utils.helper.XmlHelper;
/**
* {@link PersistenceHandler} implementation which reads the configuration from XML files. These configuration is passed
* in {@link #initialize(Map)}
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class XmlPersistenceHandler implements PersistenceHandler {
protected static final Logger logger = LoggerFactory.getLogger(XmlPersistenceHandler.class);
private Map<String, User> userMap;
private Map<String, Role> roleMap;
private boolean userMapDirty;
private boolean roleMapDirty;
private Map<String, String> parameterMap;
private long usersFileDate;
private long rolesFileDate;
private File usersPath;
private File rolesPath;
@Override
public List<User> getAllUsers() {
synchronized (this.userMap) {
return new LinkedList<>(this.userMap.values());
}
}
@Override
public List<Role> getAllRoles() {
synchronized (this.roleMap) {
return new LinkedList<>(this.roleMap.values());
}
}
@Override
public User getUser(String username) {
return this.userMap.get(username);
}
@Override
public Role getRole(String roleName) {
return this.roleMap.get(roleName);
}
@Override
public User removeUser(String username) {
User user = this.userMap.remove(username);
this.userMapDirty = user != null;
return user;
}
@Override
public Role removeRole(String roleName) {
Role role = this.roleMap.remove(roleName);
this.roleMapDirty = role != null;
return role;
}
@Override
public void addUser(User user) {
if (this.userMap.containsKey(user.getUsername()))
throw new IllegalStateException(MessageFormat.format("The user {0} already exists!", user.getUsername()));
this.userMap.put(user.getUsername(), user);
this.userMapDirty = true;
}
@Override
public void replaceUser(User user) {
if (!this.userMap.containsKey(user.getUsername()))
throw new IllegalStateException(MessageFormat
.format("The user {0} can not be replaced as it does not exiset!", user.getUsername()));
this.userMap.put(user.getUsername(), user);
this.userMapDirty = true;
}
@Override
public void addRole(Role role) {
if (this.roleMap.containsKey(role.getName()))
throw new IllegalStateException(MessageFormat.format("The role {0} already exists!", role.getName()));
this.roleMap.put(role.getName(), role);
this.roleMapDirty = true;
}
@Override
public void replaceRole(Role role) {
if (!this.roleMap.containsKey(role.getName()))
throw new IllegalStateException(
MessageFormat.format("The role {0} can not be replaced as it does not exist!", role.getName()));
this.roleMap.put(role.getName(), role);
this.roleMapDirty = true;
}
/**
* Initializes this {@link XmlPersistenceHandler} by reading the following parameters:
* <ul>
* <li>{@link XmlConstants#XML_PARAM_BASE_PATH}</li>
* <li>{@link XmlConstants#XML_PARAM_MODEL_FILE}</li>
* </ul>
*/
@Override
public void initialize(Map<String, String> paramsMap) {
// copy parameter map
this.parameterMap = Collections.unmodifiableMap(new HashMap<>(paramsMap));
// get and validate base bath
String basePath = this.parameterMap.get(XmlConstants.XML_PARAM_BASE_PATH);
File basePathF = new File(basePath);
if (!basePathF.exists() && !basePathF.isDirectory()) {
String msg = "[{0}] Defined parameter {1} does not point to a valid path at {2}"; //$NON-NLS-1$
msg = MessageFormat.format(msg, PersistenceHandler.class.getName(), XmlConstants.XML_PARAM_BASE_PATH,
basePathF.getAbsolutePath());
throw new PrivilegeException(msg);
}
// get users file name
String usersFileName = this.parameterMap.get(XmlConstants.XML_PARAM_USERS_FILE);
if (StringHelper.isEmpty(usersFileName)) {
String msg = "[{0}] Defined parameter {1} is not valid as it is empty!"; //$NON-NLS-1$
msg = MessageFormat.format(msg, PersistenceHandler.class.getName(), XmlConstants.XML_PARAM_USERS_FILE);
throw new PrivilegeException(msg);
}
// get roles file name
String rolesFileName = this.parameterMap.get(XmlConstants.XML_PARAM_ROLES_FILE);
if (StringHelper.isEmpty(rolesFileName)) {
String msg = "[{0}] Defined parameter {1} is not valid as it is empty!"; //$NON-NLS-1$
msg = MessageFormat.format(msg, PersistenceHandler.class.getName(), XmlConstants.XML_PARAM_ROLES_FILE);
throw new PrivilegeException(msg);
}
// validate users file exists
String usersPathS = basePath + "/" + usersFileName; //$NON-NLS-1$
File usersPath = new File(usersPathS);
if (!usersPath.exists()) {
String msg = "[{0}] Defined parameter {1} is invalid as users file does not exist at path {2}"; //$NON-NLS-1$
msg = MessageFormat.format(msg, PersistenceHandler.class.getName(), XmlConstants.XML_PARAM_USERS_FILE,
usersPath.getAbsolutePath());
throw new PrivilegeException(msg);
}
// validate roles file exists
String rolesPathS = basePath + "/" + rolesFileName; //$NON-NLS-1$
File rolesPath = new File(rolesPathS);
if (!rolesPath.exists()) {
String msg = "[{0}] Defined parameter {1} is invalid as roles file does not exist at path {2}"; //$NON-NLS-1$
msg = MessageFormat.format(msg, PersistenceHandler.class.getName(), XmlConstants.XML_PARAM_ROLES_FILE,
rolesPath.getAbsolutePath());
throw new PrivilegeException(msg);
}
// save path to model
this.usersPath = usersPath;
this.rolesPath = rolesPath;
if (reload())
logger.info("Privilege Data loaded."); //$NON-NLS-1$
}
/**
* Reads the XML configuration files which contain the model. Which configuration files are parsed was defined in
* the while calling {@link #initialize(Map)}
*
* @see #initialize(Map)
*/
@Override
public boolean reload() {
this.roleMap = Collections.synchronizedMap(new HashMap<String, Role>());
this.userMap = Collections.synchronizedMap(new HashMap<String, User>());
// parse models xml file to XML document
PrivilegeUsersSaxReader usersXmlHandler = new PrivilegeUsersSaxReader();
XmlHelper.parseDocument(this.usersPath, usersXmlHandler);
PrivilegeRolesSaxReader rolesXmlHandler = new PrivilegeRolesSaxReader();
XmlHelper.parseDocument(this.rolesPath, rolesXmlHandler);
this.usersFileDate = this.usersPath.lastModified();
this.rolesFileDate = this.rolesPath.lastModified();
// ROLES
List<Role> roles = rolesXmlHandler.getRoles();
for (Role role : roles) {
this.roleMap.put(role.getName(), role);
}
// USERS
List<User> users = usersXmlHandler.getUsers();
for (User user : users) {
this.userMap.put(user.getUsername(), user);
}
this.userMapDirty = false;
this.roleMapDirty = false;
logger.info(MessageFormat.format("Read {0} Users", this.userMap.size())); //$NON-NLS-1$
logger.info(MessageFormat.format("Read {0} Roles", this.roleMap.size())); //$NON-NLS-1$
// validate referenced roles exist
for (User user : users) {
for (String roleName : user.getRoles()) {
// validate that role exists
if (getRole(roleName) == null) {
String msg = "Role {0} does not exist referenced by user {1}";
msg = MessageFormat.format(msg, roleName, user.getUsername());
throw new PrivilegeException(msg);
}
}
}
return true;
}
/**
* Writes the model to the XML files. Where the files are written to was defined in the {@link #initialize(Map)}
*/
@Override
public boolean persist() {
// get users file name
String usersFileName = this.parameterMap.get(XmlConstants.XML_PARAM_USERS_FILE);
if (usersFileName == null || usersFileName.isEmpty()) {
String msg = "[{0}] Defined parameter {1} is invalid"; //$NON-NLS-1$
msg = MessageFormat.format(msg, PersistenceHandler.class.getName(), XmlConstants.XML_PARAM_USERS_FILE);
throw new PrivilegeException(msg);
}
// get roles file name
String rolesFileName = this.parameterMap.get(XmlConstants.XML_PARAM_ROLES_FILE);
if (rolesFileName == null || rolesFileName.isEmpty()) {
String msg = "[{0}] Defined parameter {1} is invalid"; //$NON-NLS-1$
msg = MessageFormat.format(msg, PersistenceHandler.class.getName(), XmlConstants.XML_PARAM_ROLES_FILE);
throw new PrivilegeException(msg);
}
boolean saved = false;
// get users file
boolean usersFileUnchanged = this.usersPath.exists() && this.usersPath.lastModified() == this.usersFileDate;
if (usersFileUnchanged && !this.userMapDirty) {
logger.warn("Not persisting of users as current file is unchanged and users data is not dirty"); //$NON-NLS-1$
} else {
// delegate writing
PrivilegeUsersDomWriter modelWriter = new PrivilegeUsersDomWriter(getAllUsers(), this.usersPath);
modelWriter.write();
this.userMapDirty = false;
saved = true;
}
// get roles file
boolean rolesFileUnchanged = this.rolesPath.exists() && this.rolesPath.lastModified() == this.rolesFileDate;
if (rolesFileUnchanged && !this.roleMapDirty) {
logger.warn("Not persisting of roles as current file is unchanged and roles data is not dirty"); //$NON-NLS-1$
} else {
// delegate writing
PrivilegeRolesDomWriter modelWriter = new PrivilegeRolesDomWriter(getAllRoles(), this.rolesPath);
modelWriter.write();
this.roleMapDirty = false;
saved = true;
}
// reset dirty states
return saved;
}
}

View File

@ -0,0 +1,105 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.helper;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import ch.eitchnet.privilege.handler.PrivilegeHandler;
import ch.eitchnet.privilege.model.internal.PrivilegeContainerModel;
import ch.eitchnet.privilege.xml.PrivilegeConfigDomWriter;
/**
* <p>
* This class is a simple application which can be used to bootstrap a new configuration for the
* {@link PrivilegeHandler}
* </p>
*
* <p>
* Simple execute the application and it will ask a few questions and then write a new set of configuration files which
* can be used to run the {@link PrivilegeHandler}
* </p>
*
* <p>
* <b>Note:</b>This class is not yet implemented!
* </p>
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
@SuppressWarnings("nls")
public class BootstrapConfigurationHelper {
// private static final Logger logger = Loggerdoc.getLogger(BootstrapConfigurationHelper.class);
private static String path;
private static String defaultPrivilegeContainerXmlFile = "Privilege.xml";
//private static String basePath = "";
//private static String modelFileName = "PrivilegeUsers.xml";
//private static String hashAlgorithm = "SHA-256";
private static String defaultPersistenceHandler = "ch.eitchnet.privilege.handler.DefaultPersistenceHandler";
private static String defaultEncryptionHandler = "ch.eitchnet.privilege.handler.DefaultEncryptionHandler";
/**
* @param args
* the args from the command line
*/
public static void main(String[] args) {
// get current directory
BootstrapConfigurationHelper.path = System.getProperty("user.dir") + "/newConfig";
// TODO ask user where to save configuration, default is pwd/newConfig/....
// see if path already exists
File pathF = new File(BootstrapConfigurationHelper.path);
if (pathF.exists()) {
throw new RuntimeException("Path already exists: " + pathF.getAbsolutePath());
}
if (!pathF.mkdirs()) {
throw new RuntimeException("Could not create path " + pathF.getAbsolutePath());
}
Map<String, String> parameterMap = new HashMap<>();
Map<String, String> encryptionHandlerParameterMap = new HashMap<>();
Map<String, String> persistenceHandlerParameterMap = new HashMap<>();
// TODO ask other questions...
parameterMap.put("autoPersistOnPasswordChange", "true");
encryptionHandlerParameterMap.put("hashAlgorithm", "SHA-256");
persistenceHandlerParameterMap.put("basePath", "./target/test");
persistenceHandlerParameterMap.put("modelXmlFile", "PrivilegeModel.xml");
PrivilegeContainerModel containerModel = new PrivilegeContainerModel();
containerModel.setParameterMap(parameterMap);
containerModel.setEncryptionHandlerClassName(defaultEncryptionHandler);
containerModel.setEncryptionHandlerParameterMap(encryptionHandlerParameterMap);
containerModel.setPersistenceHandlerClassName(defaultPersistenceHandler);
containerModel.setPersistenceHandlerParameterMap(persistenceHandlerParameterMap);
containerModel.addPolicy("DefaultPrivilege", "ch.eitchnet.privilege.policy.DefaultPrivilege");
// now perform work:
File configFile = new File(BootstrapConfigurationHelper.path + "/"
+ BootstrapConfigurationHelper.defaultPrivilegeContainerXmlFile);
PrivilegeConfigDomWriter configSaxWriter = new PrivilegeConfigDomWriter(containerModel, configFile);
configSaxWriter.write();
}
}

View File

@ -0,0 +1,123 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.helper;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import ch.eitchnet.utils.helper.StringHelper;
/**
* Simple Swing UI to create passwords
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
@SuppressWarnings("nls")
public class PasswordCreaterUI {
/**
* Launches the UI
*
* @param args
* not used
*/
public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Password creator");
frame.setLayout(new GridLayout(4, 2));
JLabel digest = new JLabel("Digest:", SwingConstants.RIGHT);
JLabel password = new JLabel("Password:", SwingConstants.RIGHT);
JLabel hash = new JLabel("Hash:", SwingConstants.RIGHT);
String[] digests = new String[] { "MD2", "MD5", "SHA-1", "SHA-256", "SHA-384", "SHA-512" };
final JComboBox<String> digestCombo = new JComboBox<>(digests);
digestCombo.setSelectedIndex(3);
final JPasswordField passwordField = new JPasswordField();
final JTextField hashField = new JTextField(150);
JButton digestBtn = new JButton("Digest");
passwordField.addKeyListener(new KeyListener() {
@Override
public void keyTyped(KeyEvent e) {
//
}
@Override
public void keyReleased(KeyEvent e) {
//
}
@Override
public void keyPressed(KeyEvent e) {
hashField.setText("");
}
});
digestBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
String digest = (String) digestCombo.getSelectedItem();
char[] passwordChar = passwordField.getPassword();
String password = new String(passwordChar);
String hash = StringHelper.hashAsHex(digest, password);
hashField.setText(hash);
} catch (Exception e1) {
e1.printStackTrace();
hashField.setText("Failed: " + e1.getLocalizedMessage());
}
}
});
frame.add(digest);
frame.add(digestCombo);
frame.add(password);
frame.add(passwordField);
frame.add(hash);
frame.add(hashField);
frame.add(new JLabel());
frame.add(digestBtn);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int width = 500;
int height = 160;
frame.setSize(width, height);
frame.setLocation(screenSize.width / 2 - width, screenSize.height / 2 - height);
frame.setVisible(true);
}
}

View File

@ -0,0 +1,72 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.helper;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.security.MessageDigest;
import ch.eitchnet.utils.helper.StringHelper;
/**
* <p>
* Simple main class which can be used to create a hash from a password which the user must type in at the command line
* </p>
*
* <p>
* TODO: Note: currently the password input is echoed which is a security risk
* </p>
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class PasswordCreator {
/**
* @param args
* the args from the command line, NOT USED
* @throws Exception
* thrown if anything goes wrong
*/
@SuppressWarnings("nls")
public static void main(String[] args) throws Exception {
BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
String hashAlgorithm = null;
while (hashAlgorithm == null) {
System.out.print("Hash Algorithm [SHA-256]: ");
String readLine = r.readLine().trim();
if (readLine.isEmpty()) {
hashAlgorithm = "SHA-256";
} else {
try {
MessageDigest.getInstance(readLine);
hashAlgorithm = readLine;
} catch (Exception e) {
System.out.println(e.getLocalizedMessage());
hashAlgorithm = null;
}
}
}
System.out.print("Password: ");
String password = r.readLine().trim();
System.out.print("Hash is: " + StringHelper.hashAsHex(hashAlgorithm, password));
}
}

View File

@ -0,0 +1,140 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.helper;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.Map;
import ch.eitchnet.privilege.base.PrivilegeException;
import ch.eitchnet.privilege.handler.DefaultPrivilegeHandler;
import ch.eitchnet.privilege.handler.EncryptionHandler;
import ch.eitchnet.privilege.handler.PersistenceHandler;
import ch.eitchnet.privilege.handler.PrivilegeHandler;
import ch.eitchnet.privilege.model.internal.PrivilegeContainerModel;
import ch.eitchnet.privilege.policy.PrivilegePolicy;
import ch.eitchnet.privilege.xml.PrivilegeConfigSaxReader;
import ch.eitchnet.utils.helper.ClassHelper;
import ch.eitchnet.utils.helper.XmlHelper;
/**
* This class implements the initializing of the {@link PrivilegeHandler} by loading an XML file containing the
* configuration
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class PrivilegeInitializationHelper {
/**
* Initializes the {@link DefaultPrivilegeHandler} from the configuration file
*
* @param privilegeXmlFile
* a {@link File} reference to the XML file containing the configuration for Privilege
*
* @return the initialized {@link PrivilegeHandler} where the {@link EncryptionHandler} and
* {@link PersistenceHandler} are set and initialized as well
*/
public static PrivilegeHandler initializeFromXml(File privilegeXmlFile) {
// make sure file exists
if (!privilegeXmlFile.exists()) {
String msg = "Privilege file does not exist at path {0}"; //$NON-NLS-1$
msg = MessageFormat.format(msg, privilegeXmlFile.getAbsolutePath());
throw new PrivilegeException(msg);
}
// delegate using input stream
try (FileInputStream fin = new FileInputStream(privilegeXmlFile)) {
return initializeFromXml(fin);
} catch (Exception e) {
String msg = "Failed to load configuration from {0}"; //$NON-NLS-1$
msg = MessageFormat.format(msg, privilegeXmlFile.getAbsolutePath());
throw new PrivilegeException(msg, e);
}
}
/**
* Initializes the {@link PrivilegeHandler} by loading from the given input stream. This stream must be a valid XML
* source
*
* @param privilegeConfigInputStream
* the XML stream containing the privilege configuration
*
* @return the initialized {@link PrivilegeHandler} where the {@link EncryptionHandler} and
* {@link PersistenceHandler} are set and initialized as well
*/
public static PrivilegeHandler initializeFromXml(InputStream privilegeConfigInputStream) {
// parse configuration file
PrivilegeContainerModel containerModel = new PrivilegeContainerModel();
PrivilegeConfigSaxReader xmlHandler = new PrivilegeConfigSaxReader(containerModel);
XmlHelper.parseDocument(privilegeConfigInputStream, xmlHandler);
return initializeFromXml(containerModel);
}
/**
* Initializes the {@link PrivilegeHandler} by initializing from the given {@link PrivilegeContainerModel}
*
* @param containerModel
* the configuration for the {@link PrivilegeHandler}
*
* @return the initialized {@link PrivilegeHandler} where the {@link EncryptionHandler} and
* {@link PersistenceHandler} are set and initialized as well
*/
public static PrivilegeHandler initializeFromXml(PrivilegeContainerModel containerModel) {
// initialize encryption handler
String encryptionHandlerClassName = containerModel.getEncryptionHandlerClassName();
EncryptionHandler encryptionHandler = ClassHelper.instantiateClass(encryptionHandlerClassName);
Map<String, String> parameterMap = containerModel.getEncryptionHandlerParameterMap();
try {
encryptionHandler.initialize(parameterMap);
} catch (Exception e) {
String msg = "EncryptionHandler {0} could not be initialized"; //$NON-NLS-1$
msg = MessageFormat.format(msg, encryptionHandlerClassName);
throw new PrivilegeException(msg, e);
}
// initialize persistence handler
String persistenceHandlerClassName = containerModel.getPersistenceHandlerClassName();
PersistenceHandler persistenceHandler = ClassHelper.instantiateClass(persistenceHandlerClassName);
parameterMap = containerModel.getPersistenceHandlerParameterMap();
try {
persistenceHandler.initialize(parameterMap);
} catch (Exception e) {
String msg = "PersistenceHandler {0} could not be initialized"; //$NON-NLS-1$
msg = MessageFormat.format(msg, persistenceHandlerClassName);
throw new PrivilegeException(msg, e);
}
// initialize privilege handler
DefaultPrivilegeHandler privilegeHandler = new DefaultPrivilegeHandler();
parameterMap = containerModel.getParameterMap();
Map<String, Class<PrivilegePolicy>> policyMap = containerModel.getPolicies();
try {
privilegeHandler.initialize(parameterMap, encryptionHandler, persistenceHandler, policyMap);
} catch (Exception e) {
String msg = "PrivilegeHandler {0} could not be initialized"; //$NON-NLS-1$
msg = MessageFormat.format(msg, privilegeHandler.getClass().getName());
throw new PrivilegeException(msg, e);
}
return privilegeHandler;
}
}

View File

@ -0,0 +1,245 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.helper;
/**
* The constants used in parsing XML documents which contain the configuration for Privilege
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
@SuppressWarnings("nls")
public class XmlConstants {
/**
* XML_ROOT_PRIVILEGE_CONTAINER = "PrivilegeContainer" :
*/
public static final String XML_ROOT_PRIVILEGE = "Privilege";
/**
* XML_CONTAINER = "Container" :
*/
public static final String XML_CONTAINER = "Container";
/**
* XML_POLICIES = "Policies" :
*/
public static final String XML_POLICIES = "Policies";
/**
* XML_PRIVILEGES = "Privileges" :
*/
public static final String XML_PRIVILEGES = "Privileges";
/**
* XML_ROOT_PRIVILEGE_USERS_AND_ROLES = "UsersAndRoles" :
*/
public static final String XML_ROOT_PRIVILEGE_USERS_AND_ROLES = "UsersAndRoles";
/**
* XML_ROOT_CERTIFICATES = "Certificates" :
*/
public static final String XML_ROOT_CERTIFICATES = "Certificates";
/**
* XML_HANDLER_PERSISTENCE = "PersistenceHandler" :
*/
public static final String XML_HANDLER_PERSISTENCE = "PersistenceHandler";
/**
* XML_HANDLER_ENCRYPTION = "EncryptionHandler" :
*/
public static final String XML_HANDLER_ENCRYPTION = "EncryptionHandler";
/**
* XML_HANDLER_PRIVILEGE = "PrivilegeHandler" :
*/
public static final String XML_HANDLER_PRIVILEGE = "PrivilegeHandler";
/**
* XML_ROLES = "Roles" :
*/
public static final String XML_ROLES = "Roles";
/**
* XML_ROLE = "Role" :
*/
public static final String XML_ROLE = "Role";
/**
* XML_USERS = "Users" :
*/
public static final String XML_USERS = "Users";
/**
* XML_CERTIFICATE = "Certificate" :
*/
public static final String XML_CERTIFICATE = "Certificate";
/**
* XML_SESSION_DATA = "SessionData" :
*/
public static final String XML_SESSION_DATA = "SessionData";
/**
* XML_USER = "User"
*/
public static final String XML_USER = "User";
/**
* XML_PRIVILEGE = "Privilege" :
*/
public static final String XML_PRIVILEGE = "Privilege";
/**
* XML_POLICY = "Policy" :
*/
public static final String XML_POLICY = "Policy";
/**
* XML_PARAMETERS = "Parameters" :
*/
public static final String XML_PARAMETERS = "Parameters";
/**
* XML_PARAMETER = "Parameter" :
*/
public static final String XML_PARAMETER = "Parameter";
/**
* XML_PROPERTIES = "Properties" :
*/
public static final String XML_PROPERTIES = "Properties";
/**
* XML_PROPERTY = "Property" :
*/
public static final String XML_PROPERTY = "Property";
/**
* XML_ALL_ALLOWED = "AllAllowed" :
*/
public static final String XML_ALL_ALLOWED = "AllAllowed";
/**
* XML_DENY = "Deny" :
*/
public static final String XML_DENY = "Deny";
/**
* XML_ALLOW = "Allow" :
*/
public static final String XML_ALLOW = "Allow";
/**
* XML_FIRSTNAME = "Firstname" :
*/
public static final String XML_FIRSTNAME = "Firstname";
/**
* XML_LASTNAME = "Lastname" :
*/
public static final String XML_LASTNAME = "Lastname";
/**
* XML_STATE = "State" :
*/
public static final String XML_STATE = "State";
/**
* XML_LOCALE = "Locale" :
*/
public static final String XML_LOCALE = "Locale";
/**
* XML_ATTR_CLASS = "class" :
*/
public static final String XML_ATTR_CLASS = "class";
/**
* XML_ATTR_LOGIN_TIME = "loginTime" :
*/
public static final String XML_ATTR_LOGIN_TIME = "loginTime";
/**
* XML_ATTR_LAST_ACCESS = "lastAccess" :
*/
public static final String XML_ATTR_LAST_ACCESS = "lastAccess";
/**
* XML_ATTR_NAME = "name" :
*/
public static final String XML_ATTR_NAME = "name";
/**
* XML_ATTR_VALUE = "value" :
*/
public static final String XML_ATTR_VALUE = "value";
/**
* XML_ATTR_POLICY = "policy" :
*/
public static final String XML_ATTR_POLICY = "policy";
/**
* XML_ATTR_USER_ID = "userId" :
*/
public static final String XML_ATTR_USER_ID = "userId";
/**
* XML_ATTR_SESSION_ID = "sessionId" :
*/
public static final String XML_ATTR_SESSION_ID = "sessionId";
/**
* XML_ATTR_USERNAME = "username" :
*/
public static final String XML_ATTR_USERNAME = "username";
/**
* XML_ATTR_AUTH_TOKEN = "authToken" :
*/
public static final String XML_ATTR_AUTH_TOKEN = "authToken";
/**
* XML_ATTR_LOCALE = "locale" :
*/
public static final String XML_ATTR_LOCALE = "locale";
/**
* XML_ATTR_PASSWORD = "password" :
*/
public static final String XML_ATTR_PASSWORD = "password";
/**
* XML_PARAM_HASH_ALGORITHM = "hashAlgorithm" :
*/
public static final String XML_PARAM_HASH_ALGORITHM = "hashAlgorithm";
/**
* XML_PARAM_USERS_FILE = "usersXmlFile" :
*/
public static final String XML_PARAM_USERS_FILE = "usersXmlFile";
/**
* XML_PARAM_ROLES_FILE = "rolesXmlFile" :
*/
public static final String XML_PARAM_ROLES_FILE = "rolesXmlFile";
/**
* XML_PARAM_BASE_PATH = "basePath" :
*/
public static final String XML_PARAM_BASE_PATH = "basePath";
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.i18n;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*
*/
public class PrivilegeMessages {
private static final String BUNDLE_NAME = "PrivilegeMessages"; //$NON-NLS-1$
private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME);
private PrivilegeMessages() {
}
public static String getString(String key) {
try {
return RESOURCE_BUNDLE.getString(key);
} catch (MissingResourceException e) {
return '!' + key + '!';
}
}
}

View File

@ -0,0 +1,316 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.model;
import java.io.Serializable;
import java.util.Collections;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import ch.eitchnet.privilege.base.PrivilegeException;
import ch.eitchnet.privilege.handler.PrivilegeHandler;
import ch.eitchnet.privilege.model.internal.User;
import ch.eitchnet.utils.helper.StringHelper;
/**
* The {@link Certificate} is the object a client keeps when accessing a Privilege enabled system. This object is the
* instance which is always used when performing an access and is returned when a user performs a login through
* {@link PrivilegeHandler#authenticate(String, byte[])}
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public final class Certificate implements Serializable {
private static final long serialVersionUID = 1L;
private final String sessionId;
private final String username;
private final String firstname;
private final String lastname;
private final UserState userState;
private final String authToken;
private final Date loginTime;
private final Set<String> userRoles;
private final Map<String, String> propertyMap;
private Locale locale;
private Date lastAccess;
/**
* Default constructor initializing with all information needed for this certificate
*
* <p>
* Note, both the authentication token and password are private fields which are generated on login and only known
* by the {@link PrivilegeHandler}
* </p>
*
* @param sessionId
* the users session id
* @param username
* the users login name
* @param firstname
* the users first name
* @param lastname
* the users last name
* @param authToken
* the authentication token defining the users unique session and is a private field of this certificate.
* @param locale
* the users {@link Locale}
* @param userRoles
* the user's roles
* @param propertyMap
* a {@link Map} containing string value pairs of properties for the logged in user. These properties can
* be edited and can be used for the user to change settings of this session
*/
public Certificate(String sessionId, String username, String firstname, String lastname, UserState userState,
String authToken, Date loginTime, Locale locale, Set<String> userRoles, Map<String, String> propertyMap) {
// validate arguments are not null
if (StringHelper.isEmpty(sessionId)) {
throw new PrivilegeException("sessionId is null!"); //$NON-NLS-1$
}
if (StringHelper.isEmpty(username)) {
throw new PrivilegeException("username is null!"); //$NON-NLS-1$
}
if (StringHelper.isEmpty(authToken)) {
throw new PrivilegeException("authToken is null!"); //$NON-NLS-1$
}
if (userState == null) {
throw new PrivilegeException("userState is null!"); //$NON-NLS-1$
}
this.sessionId = sessionId;
this.username = username;
this.firstname = firstname;
this.lastname = lastname;
this.userState = userState;
this.authToken = authToken;
this.loginTime = loginTime;
// if no locale is given, set default
if (locale == null)
this.locale = Locale.getDefault();
else
this.locale = locale;
if (propertyMap == null)
this.propertyMap = Collections.emptyMap();
else
this.propertyMap = Collections.unmodifiableMap(propertyMap);
this.userRoles = Collections.unmodifiableSet(userRoles);
}
/**
* Returns the set or roles this user has
*
* @return the user's roles
*/
public Set<String> getUserRoles() {
return this.userRoles;
}
/**
* Returns true if the user of this certificate has the given role
*
* @param role
* the role to check for
*
* @return true if the user of this certificate has the given role
*/
public boolean hasRole(String role) {
return this.userRoles.contains(role);
}
/**
* Returns the {@link User User's} property map. The map is immutable
*
* @return the propertyMap
*/
public Map<String, String> getPropertyMap() {
return this.propertyMap;
}
/**
* Returns the property with the given key
*
* @param key
* the key for which the property is to be returned
*
* @return the value of the property with the given key, or null if it does not exist
*/
public String getProperty(String key) {
return this.propertyMap.get(key);
}
/**
* @return the locale
*/
public Locale getLocale() {
return this.locale;
}
/**
* @param locale
* the locale to set
*/
public void setLocale(Locale locale) {
this.locale = locale;
}
/**
* @return the sessionId
*/
public String getSessionId() {
return this.sessionId;
}
/**
* @return the username
*/
public String getUsername() {
return this.username;
}
/**
* @return the firstname
*/
public String getFirstname() {
return this.firstname;
}
/**
* @return the lastname
*/
public String getLastname() {
return this.lastname;
}
/**
* @return the userState
*/
public UserState getUserState() {
return userState;
}
/**
* @return the loginTime
*/
public Date getLoginTime() {
return this.loginTime;
}
/**
* Returns the authToken if the given authPassword is correct, null otherwise
*
* @return the authToken if the given authPassword is correct, null otherwise
*/
public String getAuthToken() {
return this.authToken;
}
/**
* @return the lastAccess
*/
public Date getLastAccess() {
return this.lastAccess;
}
/**
* @param lastAccess
* the lastAccess to set
*/
public void setLastAccess(Date lastAccess) {
this.lastAccess = lastAccess;
}
/**
* Returns a string representation of this object displaying its concrete type and its values
*
* @see java.lang.Object#toString()
*/
@SuppressWarnings("nls")
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Certificate [sessionId=");
builder.append(this.sessionId);
builder.append(", username=");
builder.append(this.username);
if (StringHelper.isNotEmpty(this.firstname)) {
builder.append(", firstname=");
builder.append(this.firstname);
}
if (StringHelper.isNotEmpty(this.lastname)) {
builder.append(", lastname=");
builder.append(this.lastname);
}
builder.append(", locale=");
builder.append(this.locale);
builder.append("]");
return builder.toString();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((this.authToken == null) ? 0 : this.authToken.hashCode());
result = prime * result + ((this.locale == null) ? 0 : this.locale.hashCode());
result = prime * result + ((this.sessionId == null) ? 0 : this.sessionId.hashCode());
result = prime * result + ((this.username == null) ? 0 : this.username.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof Certificate))
return false;
Certificate other = (Certificate) obj;
if (this.authToken == null) {
if (other.authToken != null)
return false;
} else if (!this.authToken.equals(other.authToken))
return false;
if (this.locale == null) {
if (other.locale != null)
return false;
} else if (!this.locale.equals(other.locale))
return false;
if (this.sessionId == null) {
if (other.sessionId != null)
return false;
} else if (!this.sessionId.equals(other.sessionId))
return false;
if (this.username == null) {
if (other.username != null)
return false;
} else if (!this.username.equals(other.username))
return false;
return true;
}
}

View File

@ -0,0 +1,86 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.model;
import java.util.Set;
import ch.eitchnet.privilege.model.internal.Role;
import ch.eitchnet.privilege.policy.PrivilegePolicy;
/**
* <p>
* {@link IPrivilege} is the main model object for Privilege. A {@link Role} has a set of Privileges assigned to it
* which defines the privileges a logged in user with that role has. If the {@link IPrivilege} has a
* {@link PrivilegePolicy} defined, then that policy will be used for finer granularity and with the deny and allow
* lists configured which is used to evaluate if privilege is granted to a {@link Restrictable}
* </p>
*
* @author Robert von Burg <eitch@eitchnet.ch>
*
*/
public interface IPrivilege {
/**
* @return a {@link PrivilegeRep} which is a representation of this object used to serialize and view on clients
*/
public abstract PrivilegeRep asPrivilegeRep();
/**
* @return the name
*/
public abstract String getName();
/**
* @return the policy
*/
public abstract String getPolicy();
/**
* @return the allAllowed
*/
public abstract boolean isAllAllowed();
/**
* @return the allowList
*/
public abstract Set<String> getAllowList();
/**
* @return the denyList
*/
public abstract Set<String> getDenyList();
/**
* @return true if there are values in the allow list
*/
public abstract boolean hasAllowed();
/**
* @return if the value is in the allow list
*/
public abstract boolean isAllowed(String value);
/**
* @return true if there are values in the deny list
*/
public abstract boolean hasDenied();
/**
* @return true if the value is in the deny list
*/
public abstract boolean isDenied(String value);
}

View File

@ -0,0 +1,131 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.model;
import java.text.MessageFormat;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import ch.eitchnet.privilege.base.AccessDeniedException;
import ch.eitchnet.privilege.base.PrivilegeException;
import ch.eitchnet.privilege.i18n.PrivilegeMessages;
import ch.eitchnet.privilege.policy.PrivilegePolicy;
/**
* This context gives access to a logged in user's privilege data e.g. the {@link UserRep}, {@link Certificate} and the
* user's list of {@link PrivilegeRep}
*
* <p>
* Note: This is an internal object which is not to be serialized to clients
* </p>
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class PrivilegeContext {
//
// object state
//
private UserRep userRep;
private Certificate certificate;
private Map<String, IPrivilege> privileges;
private Map<String, PrivilegePolicy> policies;
public PrivilegeContext(UserRep userRep, Certificate certificate, Map<String, IPrivilege> privileges,
Map<String, PrivilegePolicy> policies) {
this.userRep = userRep;
this.certificate = certificate;
this.privileges = Collections.unmodifiableMap(new HashMap<>(privileges));
this.policies = Collections.unmodifiableMap(new HashMap<>(policies));
}
public UserRep getUserRep() {
return this.userRep;
}
public Certificate getCertificate() {
return this.certificate;
}
public String getUsername() {
return this.userRep.getUsername();
}
public Set<String> getPrivilegeNames() {
return this.privileges.keySet();
}
public void assertHasPrivilege(String privilegeName) {
if (!this.privileges.containsKey(privilegeName)) {
String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.noprivilege.user"), //$NON-NLS-1$
userRep.getUsername(), privilegeName);
throw new AccessDeniedException(msg);
}
}
public IPrivilege getPrivilege(String privilegeName) {
assertHasPrivilege(privilegeName);
return this.privileges.get(privilegeName);
}
public PrivilegePolicy getPolicy(String policyName) {
PrivilegePolicy policy = this.policies.get(policyName);
if (policy == null) {
String msg = "The PrivilegePolicy {0} does not exist on the PrivilegeContext!"; //$NON-NLS-1$
throw new PrivilegeException(MessageFormat.format(msg, policyName));
}
return policy;
}
//
// business logic
//
/**
* Validates if the user for this context has the privilege to access to the given {@link Restrictable}. If the user
* has the privilege, then this method returns with no exception and void, if the user does not have the privilege,
* then a {@link AccessDeniedException} is thrown.
*
* @param restrictable
* the {@link Restrictable} which the user wants to access
*
* @throws AccessDeniedException
* if the user does not have access
* @throws PrivilegeException
* if there is an internal error due to wrongly configured privileges or programming errors
*/
public void validateAction(Restrictable restrictable) throws AccessDeniedException, PrivilegeException {
// the privilege for the restrictable
String privilegeName = restrictable.getPrivilegeName();
IPrivilege privilege = this.privileges.get(privilegeName);
if (privilege == null) {
String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.accessdenied.noprivilege"), //$NON-NLS-1$
getUsername(), privilegeName, restrictable.getClass().getName());
throw new AccessDeniedException(msg);
}
// get the policy referenced by the restrictable
String policyName = privilege.getPolicy();
PrivilegePolicy policy = getPolicy(policyName);
// delegate to the policy
policy.validateAction(this, privilege, restrictable);
}
}

View File

@ -0,0 +1,236 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.model;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import ch.eitchnet.privilege.base.PrivilegeException;
import ch.eitchnet.privilege.handler.PrivilegeHandler;
import ch.eitchnet.privilege.model.internal.Role;
import ch.eitchnet.privilege.policy.PrivilegePolicy;
import ch.eitchnet.utils.helper.StringHelper;
/**
* To keep certain details of the {@link IPrivilege} itself hidden from remote clients and make sure instances are only
* edited by users with the correct privilege, this representational version is allowed to be viewed by remote clients
* and simply wraps all public data from the {@link IPrivilege}
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
@XmlRootElement(name = "Privilege")
@XmlAccessorType(XmlAccessType.NONE)
public class PrivilegeRep implements Serializable {
private static final long serialVersionUID = 1L;
@XmlAttribute(name = "name")
private String name;
@XmlAttribute(name = "policy")
private String policy;
@XmlAttribute(name = "allAllowed")
private boolean allAllowed;
@XmlElement(name = "denyList")
private Set<String> denyList;
@XmlElement(name = "allowList")
private Set<String> allowList;
/**
* Default constructor
*
* @param name
* the name of this privilege, which is unique to all privileges known in the {@link PrivilegeHandler}
* @param policy
* the {@link PrivilegePolicy} configured to evaluate if the privilege is granted
* @param allAllowed
* a boolean defining if a {@link Role} with this {@link IPrivilege} has unrestricted access to a
* {@link Restrictable}
* @param denyList
* a list of deny rules for this {@link IPrivilege}
* @param allowList
* a list of allow rules for this {@link IPrivilege}
*/
public PrivilegeRep(String name, String policy, boolean allAllowed, Set<String> denyList, Set<String> allowList) {
this.name = name;
this.policy = policy;
this.allAllowed = allAllowed;
this.denyList = denyList;
this.allowList = allowList;
}
/**
*
*/
@SuppressWarnings("unused")
private PrivilegeRep() {
// no-arg constructor for JAXB
}
/**
* Validates that all required fields are set
*/
public void validate() {
if (StringHelper.isEmpty(this.name)) {
throw new PrivilegeException("No name defined!"); //$NON-NLS-1$
}
if (StringHelper.isEmpty(this.policy)) {
throw new PrivilegeException("policy is null!"); //$NON-NLS-1$
}
if (this.denyList == null) {
throw new PrivilegeException("denyList is null"); //$NON-NLS-1$
}
if (this.allowList == null) {
throw new PrivilegeException("allowList is null"); //$NON-NLS-1$
}
}
/**
* @return the name
*/
public String getName() {
return this.name;
}
/**
* @param name
* the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the policy
*/
public String getPolicy() {
return this.policy;
}
/**
* @param policy
* the policy to set
*/
public void setPolicy(String policy) {
this.policy = policy;
}
/**
* @return the allAllowed
*/
public boolean isAllAllowed() {
return this.allAllowed;
}
/**
* @param allAllowed
* the allAllowed to set
*/
public void setAllAllowed(boolean allAllowed) {
this.allAllowed = allAllowed;
}
/**
* @return the denyList
*/
public Set<String> getDenyList() {
return this.denyList == null ? new HashSet<>() : this.denyList;
}
/**
* @param denyList
* the denyList to set
*/
public void setDenyList(Set<String> denyList) {
this.denyList = denyList;
}
/**
* @return the allowList
*/
public Set<String> getAllowList() {
return this.allowList == null ? new HashSet<>() : this.allowList;
}
/**
* @param allowList
* the allowList to set
*/
public void setAllowList(Set<String> allowList) {
this.allowList = allowList;
}
/**
* Returns a string representation of this object displaying its concrete type and its values
*
* @see java.lang.Object#toString()
*/
@SuppressWarnings("nls")
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("PrivilegeRep [name=");
builder.append(this.name);
builder.append(", policy=");
builder.append(this.policy);
builder.append(", allAllowed=");
builder.append(this.allAllowed);
builder.append(", denyList=");
builder.append((this.denyList == null ? "null" : this.denyList.size()));
builder.append(", allowList=");
builder.append((this.allowList == null ? "null" : this.allowList.size()));
builder.append("]");
return builder.toString();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((this.name == null) ? 0 : this.name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
PrivilegeRep other = (PrivilegeRep) obj;
if (this.name == null) {
if (other.name != null)
return false;
} else if (!this.name.equals(other.name))
return false;
return true;
}
}

View File

@ -0,0 +1,46 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.model;
import ch.eitchnet.privilege.policy.PrivilegePolicy;
/**
* <p>
* Objects implementing this interface are used to grant/restrict privileges to them. A {@link PrivilegePolicy}
* implements the logic on granting/restricting privileges for a {@link Restrictable} and the
* {@link #getPrivilegeName()} is used to find the {@link IPrivilege} which has the associated {@link PrivilegePolicy}
* for evaluating access
* </p>
*
* @author Robert von Burg <eitch@eitchnet.ch>
*
*/
public interface Restrictable {
/**
* Returns the name of the {@link IPrivilege} which is to be used to validate privileges against
*
* @return the name of the {@link IPrivilege} which is to be used to validate privileges against
*/
public String getPrivilegeName();
/**
* Returns the value which defines or describes what privilege is to be granted
*
* @return the value which defines or describes what privilege is to be granted
*/
public Object getPrivilegeValue();
}

View File

@ -0,0 +1,168 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.model;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import ch.eitchnet.privilege.base.PrivilegeException;
import ch.eitchnet.privilege.model.internal.Role;
import ch.eitchnet.utils.helper.StringHelper;
/**
* To keep certain details of the {@link Role} itself hidden from remote clients and make sure instances are only edited
* by users with the correct privilege, this representational version is allowed to be viewed by remote clients and
* simply wraps all public data from the {@link Role}
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
@XmlRootElement(name = "Role")
@XmlAccessorType(XmlAccessType.NONE)
public class RoleRep implements Serializable {
private static final long serialVersionUID = 1L;
@XmlAttribute(name = "name")
private String name;
@XmlElement(name = "privileges")
private List<PrivilegeRep> privileges;
/**
* Default constructor
*
* @param name
* the name of this role
* @param privileges
* the list of privileges granted to this role
*/
public RoleRep(String name, List<PrivilegeRep> privileges) {
this.name = name;
this.privileges = privileges;
}
/**
*
*/
@SuppressWarnings("unused")
private RoleRep() {
// no-arg constructor for JAXB
}
/**
* validates that all required fields are set
*/
public void validate() {
if (StringHelper.isEmpty(this.name))
throw new PrivilegeException("name is null"); //$NON-NLS-1$
if (this.privileges != null && !this.privileges.isEmpty()) {
for (PrivilegeRep privilege : this.privileges) {
try {
privilege.validate();
} catch (Exception e) {
String msg = "Privilege {0} is invalid on role {1}";
msg = MessageFormat.format(msg, privilege.getName(), this.name);
throw new PrivilegeException(msg, e);
}
}
}
}
/**
* @return the name
*/
public String getName() {
return this.name;
}
/**
* @param name
* the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* Returns the privileges assigned to this Role as a list
*
* @return the privileges assigned to this Role as a list
*/
public List<PrivilegeRep> getPrivileges() {
return this.privileges == null ? new ArrayList<>() : this.privileges;
}
/**
* Sets the privileges on this from a list
*
* @param privileges
* the list of privileges to assign to this role
*/
public void setPrivileges(List<PrivilegeRep> privileges) {
this.privileges = privileges;
}
/**
* Returns a string representation of this object displaying its concrete type and its values
*
* @see java.lang.Object#toString()
*/
@SuppressWarnings("nls")
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("RoleRep [name=");
builder.append(this.name);
builder.append(", privilegeMap=");
builder.append((this.privileges == null ? "null" : this.privileges));
builder.append("]");
return builder.toString();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((this.name == null) ? 0 : this.name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
RoleRep other = (RoleRep) obj;
if (this.name == null) {
if (other.name != null)
return false;
} else if (!this.name.equals(other.name))
return false;
return true;
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.model;
import ch.eitchnet.utils.dbc.DBC;
public class SimpleRestrictable implements Restrictable {
private final String name;
private final Object value;
/**
* @param name
* @param value
*/
public SimpleRestrictable(String name, Object value) {
DBC.PRE.assertNotEmpty("name must not be emepty", name);
DBC.PRE.assertNotNull("value must not be null", value);
this.name = name;
this.value = value;
}
@Override
public String getPrivilegeName() {
return this.name;
}
@Override
public Object getPrivilegeValue() {
return this.value;
}
}

View File

@ -0,0 +1,388 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import ch.eitchnet.privilege.base.PrivilegeException;
import ch.eitchnet.privilege.model.internal.Role;
import ch.eitchnet.privilege.model.internal.User;
import ch.eitchnet.utils.helper.StringHelper;
import ch.eitchnet.utils.xml.XmlKeyValue;
/**
* To keep certain details of the {@link User} itself hidden from remote clients and make sure instances are only edited
* by users with the correct privilege, this representational version is allowed to be viewed by remote clients and
* simply wraps all public data from the {@link User}
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
@XmlRootElement(name = "User")
@XmlAccessorType(XmlAccessType.NONE)
public class UserRep implements Serializable {
private static final long serialVersionUID = 1L;
@XmlAttribute(name = "userId")
private String userId;
@XmlAttribute(name = "username")
private String username;
@XmlAttribute(name = "firstname")
private String firstname;
@XmlAttribute(name = "lastname")
private String lastname;
@XmlAttribute(name = "userState")
private UserState userState;
@XmlAttribute(name = "locale")
private Locale locale;
@XmlElement(name = "roles")
private Set<String> roles;
@XmlElement(name = "properties")
private List<XmlKeyValue> properties;
/**
* Default constructor
*
* @param userId
* the user's id
* @param username
* the user's login name
* @param firstname
* the user's first name
* @param lastname
* the user's last name
* @param userState
* the user's {@link UserState}
* @param roles
* the set of {@link Role}s assigned to this user
* @param locale
* the user's {@link Locale}
* @param propertyMap
* a {@link Map} containing string value pairs of properties for this user
*/
public UserRep(String userId, String username, String firstname, String lastname, UserState userState,
Set<String> roles, Locale locale, Map<String, String> propertyMap) {
this.userId = userId;
this.username = username;
this.firstname = firstname;
this.lastname = lastname;
this.userState = userState;
this.roles = roles;
this.locale = locale;
this.properties = propertyMap == null ? new ArrayList<>() : XmlKeyValue.valueOf(propertyMap);
}
/**
*
*/
@SuppressWarnings("unused")
private UserRep() {
// No arg constructor for JAXB
}
/**
* Validates that all required fields are set
*/
public void validate() {
if (StringHelper.isEmpty(this.userId))
throw new PrivilegeException("userId is null or empty"); //$NON-NLS-1$
if (StringHelper.isEmpty(this.username))
throw new PrivilegeException("username is null or empty"); //$NON-NLS-1$
if (this.userState == null)
throw new PrivilegeException("userState is null"); //$NON-NLS-1$
if (StringHelper.isEmpty(this.firstname))
throw new PrivilegeException("firstname is null or empty"); //$NON-NLS-1$
if (StringHelper.isEmpty(this.lastname))
throw new PrivilegeException("lastname is null or empty"); //$NON-NLS-1$
if (this.roles == null || this.roles.isEmpty())
throw new PrivilegeException("roles is null or empty"); //$NON-NLS-1$
}
/**
* @return the userId
*/
public String getUserId() {
return this.userId;
}
/**
* Set the userId
*
* @param userId
* to set
*/
public void setUserId(String userId) {
this.userId = userId;
}
/**
* @return the username
*/
public String getUsername() {
return this.username;
}
/**
* @param username
* the username to set
*/
public void setUsername(String username) {
this.username = username;
}
/**
* @return the firstname
*/
public String getFirstname() {
return this.firstname;
}
/**
* @param firstname
* the firstname to set
*/
public void setFirstname(String firstname) {
this.firstname = firstname;
}
/**
* @return the lastname
*/
public String getLastname() {
return this.lastname;
}
/**
* @param lastname
* the lastname to set
*/
public void setLastname(String lastname) {
this.lastname = lastname;
}
/**
* @return the userState
*/
public UserState getUserState() {
return this.userState;
}
/**
* @param userState
* the userState to set
*/
public void setUserState(UserState userState) {
this.userState = userState;
}
/**
* @return the roles
*/
public Set<String> getRoles() {
return this.roles;
}
/**
* @param roles
* the roles to set
*/
public void setRoles(Set<String> roles) {
this.roles = roles;
}
/**
* @return the locale
*/
public Locale getLocale() {
return this.locale;
}
/**
* @param locale
* the locale to set
*/
public void setLocale(Locale locale) {
this.locale = locale;
}
/**
* Returns the property with the given key
*
* @param key
* the key for which the property is to be returned
*
* @return the property with the given key, or null if the property is not defined
*/
public String getProperty(String key) {
if (this.properties == null)
return null;
for (XmlKeyValue keyValue : this.properties) {
if (keyValue.getKey().equals(key))
return keyValue.getValue();
}
return null;
}
/**
* Set the property with the key to the value
*
* @param key
* the key of the property to set
* @param value
* the value of the property to set
*/
public void setProperty(String key, String value) {
if (this.properties == null)
this.properties = new ArrayList<>();
boolean updated = false;
for (XmlKeyValue keyValue : this.properties) {
if (keyValue.getKey().equals(key)) {
keyValue.setValue(value);
updated = true;
}
}
if (!updated) {
this.properties.add(new XmlKeyValue(key, value));
}
}
/**
* Returns the {@link Set} of keys of all properties
*
* @return the {@link Set} of keys of all properties
*/
public Set<String> getPropertyKeySet() {
if (this.properties == null)
return new HashSet<>();
Set<String> keySet = new HashSet<>(this.properties.size());
for (XmlKeyValue keyValue : this.properties) {
keySet.add(keyValue.getKey());
}
return keySet;
}
/**
* Returns the map of properties
*
* @return the map of properties
*/
public Map<String, String> getPropertyMap() {
if (this.properties == null)
return new HashMap<>();
return XmlKeyValue.toMap(this.properties);
}
/**
* Returns the string map properties of this user as a list of {@link XmlKeyValue} elements
*
* @return the string map properties of this user as a list of {@link XmlKeyValue} elements
*/
@XmlElement(name = "properties")
public List<XmlKeyValue> getProperties() {
return this.properties == null ? new ArrayList<>() : this.properties;
}
/**
* Sets the string map properties of this user from the given list of {@link XmlKeyValue}
*
* @param values
* the list of {@link XmlKeyValue} from which to set the properties
*/
public void setProperties(List<XmlKeyValue> values) {
this.properties = values;
}
/**
* Returns a string representation of this object displaying its concrete type and its values
*
* @see java.lang.Object#toString()
*/
@SuppressWarnings("nls")
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("UserRep [userId=");
builder.append(this.userId);
builder.append(", username=");
builder.append(this.username);
builder.append(", firstname=");
builder.append(this.firstname);
builder.append(", lastname=");
builder.append(this.lastname);
builder.append(", userState=");
builder.append(this.userState);
builder.append(", locale=");
builder.append(this.locale);
builder.append(", roles=");
builder.append(this.roles);
builder.append("]");
return builder.toString();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((this.username == null) ? 0 : this.username.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
UserRep other = (UserRep) obj;
if (this.username == null) {
if (other.username != null)
return false;
} else if (!this.username.equals(other.username))
return false;
return true;
}
}

View File

@ -0,0 +1,60 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.model;
import ch.eitchnet.privilege.model.internal.User;
/**
* The {@link UserState} enum defines the different states a {@link User} can have:
* <ul>
* <li>NEW - the user is new, and cannot login</li>
* <li>ENABLED - the user has been enabled, meaning a password has been set and the user has at least one role assigned
* and may thus login</li>
* <li>DISABLED - the user been disabled by an administrator</li>
* <li>EXPIRED - the user has automatically expired through a predefined time</li>
* </ul>
*
* @author Robert von Burg <eitch@eitchnet.ch>
*
*/
public enum UserState {
/**
* the user is new, and cannot login
*/
NEW,
/**
* the user has been enabled, meaning a password has been set and the user has at least one role assigned and may
* thus login
*/
ENABLED,
/**
* the user been disabled by an administrator
*/
DISABLED,
/**
* the user has automatically expired through a predefined time
*/
EXPIRED,
/**
* This is the System user state which is special and thus exempted from normal uses
*/
SYSTEM;
public boolean isSystem() {
return this == UserState.SYSTEM;
}
}

View File

@ -0,0 +1,188 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.model.internal;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import ch.eitchnet.privilege.base.PrivilegeException;
import ch.eitchnet.privilege.handler.PrivilegeHandler;
import ch.eitchnet.privilege.policy.PrivilegePolicy;
/**
* This class is used during XML parsing to hold the model before it is properly validated and made accessible through
* the {@link PrivilegeHandler}
*
* <p>
* Note: This is an internal object which is not to be serialized or passed to clients
* </p>
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class PrivilegeContainerModel {
private String encryptionHandlerClassName;
private Map<String, String> encryptionHandlerParameterMap;
private String persistenceHandlerClassName;
private Map<String, String> persistenceHandlerParameterMap;
private Map<String, String> parameterMap;
private Map<String, Class<PrivilegePolicy>> policies;
/**
* Default constructor
*/
public PrivilegeContainerModel() {
this.policies = new HashMap<>();
}
/**
* @return the parameterMap
*/
public Map<String, String> getParameterMap() {
return this.parameterMap;
}
/**
* @param parameterMap
* the parameterMap to set
*/
public void setParameterMap(Map<String, String> parameterMap) {
this.parameterMap = parameterMap;
}
/**
* @return the encryptionHandlerClassName
*/
public String getEncryptionHandlerClassName() {
return this.encryptionHandlerClassName;
}
/**
* @param encryptionHandlerClassName
* the encryptionHandlerClassName to set
*/
public void setEncryptionHandlerClassName(String encryptionHandlerClassName) {
this.encryptionHandlerClassName = encryptionHandlerClassName;
}
/**
* @return the encryptionHandlerParameterMap
*/
public Map<String, String> getEncryptionHandlerParameterMap() {
return this.encryptionHandlerParameterMap;
}
/**
* @param encryptionHandlerParameterMap
* the encryptionHandlerParameterMap to set
*/
public void setEncryptionHandlerParameterMap(Map<String, String> encryptionHandlerParameterMap) {
this.encryptionHandlerParameterMap = encryptionHandlerParameterMap;
}
/**
* @return the persistenceHandlerClassName
*/
public String getPersistenceHandlerClassName() {
return this.persistenceHandlerClassName;
}
/**
* @param persistenceHandlerClassName
* the persistenceHandlerClassName to set
*/
public void setPersistenceHandlerClassName(String persistenceHandlerClassName) {
this.persistenceHandlerClassName = persistenceHandlerClassName;
}
/**
* @return the persistenceHandlerParameterMap
*/
public Map<String, String> getPersistenceHandlerParameterMap() {
return this.persistenceHandlerParameterMap;
}
/**
* @param persistenceHandlerParameterMap
* the persistenceHandlerParameterMap to set
*/
public void setPersistenceHandlerParameterMap(Map<String, String> persistenceHandlerParameterMap) {
this.persistenceHandlerParameterMap = persistenceHandlerParameterMap;
}
/**
* @param privilegeName
* @param policyClassName
*/
public void addPolicy(String privilegeName, String policyClassName) {
try {
// load class and try to create a new instance
@SuppressWarnings("unchecked")
Class<PrivilegePolicy> clazz = (Class<PrivilegePolicy>) Class.forName(policyClassName);
clazz.newInstance();
this.policies.put(privilegeName, clazz);
} catch (InstantiationException e) {
String msg = "Configured Privilege Policy {0} with class {1} could not be instantiated."; //$NON-NLS-1$
msg = MessageFormat.format(msg, privilegeName, policyClassName);
throw new PrivilegeException(msg, e);
} catch (IllegalAccessException e) {
String msg = "Configured Privilege Policy {0} with class {1} can not be accessed."; //$NON-NLS-1$
msg = MessageFormat.format(msg, privilegeName, policyClassName);
throw new PrivilegeException(msg, e);
} catch (ClassNotFoundException e) {
String msg = "Configured Privilege Policy {0} with class {1} does not exist."; //$NON-NLS-1$
msg = MessageFormat.format(msg, privilegeName, policyClassName);
throw new PrivilegeException(msg, e);
}
}
/**
* @return the policies
*/
public Map<String, Class<PrivilegePolicy>> getPolicies() {
return this.policies;
}
/**
* Returns a string representation of this object displaying its concrete type and its values
*
* @see java.lang.Object#toString()
*/
@SuppressWarnings("nls")
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("PrivilegeContainerModel [encryptionHandlerClassName=");
builder.append(this.encryptionHandlerClassName);
builder.append(", encryptionHandlerParameterMap=");
builder.append(this.encryptionHandlerParameterMap.size());
builder.append(", persistenceHandlerClassName=");
builder.append(this.persistenceHandlerClassName);
builder.append(", persistenceHandlerParameterMap=");
builder.append(this.persistenceHandlerParameterMap.size());
builder.append(", parameterMap=");
builder.append(this.parameterMap.size());
builder.append(", policies=");
builder.append(this.policies.size());
builder.append("]");
return builder.toString();
}
}

View File

@ -0,0 +1,229 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.model.internal;
import java.text.MessageFormat;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import ch.eitchnet.privilege.base.PrivilegeException;
import ch.eitchnet.privilege.handler.PrivilegeHandler;
import ch.eitchnet.privilege.model.IPrivilege;
import ch.eitchnet.privilege.model.PrivilegeRep;
import ch.eitchnet.privilege.model.Restrictable;
import ch.eitchnet.privilege.policy.PrivilegePolicy;
import ch.eitchnet.utils.helper.StringHelper;
/**
* <p>
* {@link IPrivilege} is the main model object for Privilege. A {@link Role} has a set of Privileges assigned to it
* which defines the privileges a logged in user with that role has. If the {@link IPrivilege} has a
* {@link PrivilegePolicy} defined, then that policy will be used for finer granularity and with the deny and allow
* lists configured which is used to evaluate if privilege is granted to a {@link Restrictable}
* </p>
*
* <p>
* {@link IPrivilege}s have allow and deny rules which the configured {@link PrivilegeHandler} uses to
* </p>
*
* <p>
* Note: This is an internal object which is not to be serialized or passed to clients, {@link PrivilegeRep}s are used
* for that
* </p>
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public final class PrivilegeImpl implements IPrivilege {
private final String name;
private final String policy;
private final boolean allAllowed;
private final Set<String> denyList;
private final Set<String> allowList;
/**
* Default constructor
*
* @param name
* the name of this privilege, which is unique to all privileges known in the {@link PrivilegeHandler}
* @param policy
* the {@link PrivilegePolicy} configured to evaluate if the privilege is granted. If null, then
* privilege is granted
* @param allAllowed
* a boolean defining if a {@link Role} with this {@link PrivilegeImpl} has unrestricted access to a
* {@link Restrictable} in which case the deny and allow lists are ignored and can be null
* @param denyList
* a list of deny rules for this {@link PrivilegeImpl}, can be null if all allowed
* @param allowList
* a list of allow rules for this {@link PrivilegeImpl}, can be null if all allowed
*/
public PrivilegeImpl(String name, String policy, boolean allAllowed, Set<String> denyList, Set<String> allowList) {
if (StringHelper.isEmpty(name)) {
throw new PrivilegeException("No name defined!"); //$NON-NLS-1$
}
if (StringHelper.isEmpty(policy)) {
throw new PrivilegeException(MessageFormat.format("Policy may not be empty for Privilege {0}!", name)); //$NON-NLS-1$
}
if (denyList == null) {
throw new PrivilegeException(MessageFormat.format("denyList is null for Privilege {0}!", name)); //$NON-NLS-1$
}
if (allowList == null) {
throw new PrivilegeException(MessageFormat.format("allowList is null for Privilege {0}!", name)); //$NON-NLS-1$
}
this.name = name;
this.allAllowed = allAllowed;
this.policy = policy;
this.denyList = Collections.unmodifiableSet(denyList);
this.allowList = Collections.unmodifiableSet(allowList);
}
/**
* Constructs a {@link PrivilegeImpl} from the {@link PrivilegeRep}
*
* @param privilegeRep
* the {@link PrivilegeRep} from which to create the {@link PrivilegeImpl}
*/
public PrivilegeImpl(PrivilegeRep privilegeRep) {
this(privilegeRep.getName(), privilegeRep.getPolicy(), privilegeRep.isAllAllowed(), privilegeRep.getDenyList(),
privilegeRep.getAllowList());
}
/**
* @return a {@link PrivilegeRep} which is a representation of this object used to serialize and view on clients
*/
@Override
public PrivilegeRep asPrivilegeRep() {
return new PrivilegeRep(this.name, this.policy, this.allAllowed, new HashSet<>(this.denyList),
new HashSet<>(this.allowList));
}
/**
* @return the name
*/
@Override
public String getName() {
return this.name;
}
/**
* @return the policy
*/
@Override
public String getPolicy() {
return this.policy;
}
/**
* @return the allAllowed
*/
@Override
public boolean isAllAllowed() {
return this.allAllowed;
}
/**
* @return the allowList
*/
@Override
public Set<String> getAllowList() {
return this.allowList;
}
/**
* @return the denyList
*/
@Override
public Set<String> getDenyList() {
return this.denyList;
}
/**
* @return true if there are values in the allow list
*/
@Override
public boolean hasAllowed() {
return !this.allowList.isEmpty();
}
/**
* @return if the value is in the allow list
*/
@Override
public boolean isAllowed(String value) {
return this.allowList.contains(value);
}
/**
* @return true if there are values in the deny list
*/
@Override
public boolean hasDenied() {
return !this.allowList.isEmpty();
}
/**
* @return true if the value is in the deny list
*/
@Override
public boolean isDenied(String value) {
return this.denyList.contains(value);
}
/**
* Returns a string representation of this object displaying its concrete type and its values
*
* @see java.lang.Object#toString()
*/
@SuppressWarnings("nls")
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Privilege [name=");
builder.append(this.name);
builder.append(", policy=");
builder.append(this.policy);
builder.append("]");
return builder.toString();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((this.name == null) ? 0 : this.name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
PrivilegeImpl other = (PrivilegeImpl) obj;
if (this.name == null) {
if (other.name != null)
return false;
} else if (!this.name.equals(other.name))
return false;
return true;
}
}

View File

@ -0,0 +1,187 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.model.internal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import ch.eitchnet.privilege.base.PrivilegeException;
import ch.eitchnet.privilege.model.IPrivilege;
import ch.eitchnet.privilege.model.PrivilegeRep;
import ch.eitchnet.privilege.model.RoleRep;
import ch.eitchnet.utils.helper.StringHelper;
/**
* <p>
* A {@link User} is assigned a set of roles. These roles have a set of privileges assigned to them by name and they
* define the privileges granted to a user with this role
* </p>
*
* <p>
* Note: This is an internal object which is not to be serialized or passed to clients, {@link RoleRep}s are used for
* that
* </p>
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public final class Role {
private final String name;
private final Map<String, IPrivilege> privilegeMap;
/**
* Default constructor
*
* @param name
* the name of the role
* @param privilegeMap
* a map of {@link IPrivilege}s granted to this role
*/
public Role(String name, Map<String, IPrivilege> privilegeMap) {
if (StringHelper.isEmpty(name)) {
throw new PrivilegeException("No name defined!"); //$NON-NLS-1$
}
if (privilegeMap == null) {
throw new PrivilegeException("No privileges defined!"); //$NON-NLS-1$
}
this.name = name;
this.privilegeMap = Collections.unmodifiableMap(privilegeMap);
}
/**
* Construct {@link Role} from its representation {@link RoleRep}
*
* @param roleRep
* the representation from which to create the {@link Role}
*/
public Role(RoleRep roleRep) {
String name = roleRep.getName();
if (StringHelper.isEmpty(name)) {
throw new PrivilegeException("No name defined!"); //$NON-NLS-1$
}
if (roleRep.getPrivileges() == null) {
throw new PrivilegeException("Privileges may not be null!"); //$NON-NLS-1$
}
// build privileges from rep
Map<String, IPrivilege> privilegeMap = new HashMap<>(roleRep.getPrivileges().size());
for (PrivilegeRep privilege : roleRep.getPrivileges()) {
privilegeMap.put(privilege.getName(), new PrivilegeImpl(privilege));
}
this.name = name;
this.privilegeMap = Collections.unmodifiableMap(privilegeMap);
}
/**
* @return the name
*/
public String getName() {
return this.name;
}
/**
* Returns the {@link Set} of names for the currently stored {@link IPrivilege Privileges}
*
* @return the {@link Set} of names for the currently stored {@link IPrivilege Privileges}
*/
public Set<String> getPrivilegeNames() {
return this.privilegeMap.keySet();
}
/**
* Returns the {@link IPrivilege} for the given name, null if it does not exist
*
* @return the {@link IPrivilege} for the given name, null if it does not exist
*/
public IPrivilege getPrivilege(String name) {
return this.privilegeMap.get(name);
}
/**
* Determines if this {@link Role} has the {@link IPrivilege} with the given name
*
* @param name
* the name of the {@link IPrivilege}
*
* @return true if this {@link Role} has the {@link IPrivilege} with the given name
*/
public boolean hasPrivilege(String name) {
return this.privilegeMap.containsKey(name);
}
/**
* @return a {@link RoleRep} which is a representation of this object used to serialize and view on clients
*/
public RoleRep asRoleRep() {
List<PrivilegeRep> privileges = new ArrayList<>();
for (Entry<String, IPrivilege> entry : this.privilegeMap.entrySet()) {
privileges.add(entry.getValue().asPrivilegeRep());
}
return new RoleRep(this.name, privileges);
}
/**
* Returns a string representation of this object displaying its concrete type and its values
*
* @see java.lang.Object#toString()
*/
@SuppressWarnings("nls")
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Role [name=");
builder.append(this.name);
builder.append(", privileges=");
builder.append(this.privilegeMap.keySet());
builder.append("]");
return builder.toString();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((this.name == null) ? 0 : this.name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Role other = (Role) obj;
if (this.name == null) {
if (other.name != null)
return false;
} else if (!this.name.equals(other.name))
return false;
return true;
}
}

View File

@ -0,0 +1,291 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.model.internal;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import ch.eitchnet.privilege.base.PrivilegeException;
import ch.eitchnet.privilege.model.UserRep;
import ch.eitchnet.privilege.model.UserState;
import ch.eitchnet.utils.helper.StringHelper;
/**
* This class defines the actual login information for a given user which can be granted privileges. Every user is
* granted a set of {@link Role}s and has a {@link UserState} including detail information like first name and lastname
*
* <p>
* Note: This is an internal object which is not to be serialized or passed to clients, {@link UserRep}s are used for
* that
* </p>
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public final class User {
private final String userId;
private final String username;
private final String password;
private final String firstname;
private final String lastname;
private final UserState userState;
private final Set<String> roles;
private final Map<String, String> propertyMap;
private final Locale locale;
/**
* Default constructor
*
* @param userId
* the user's id
* @param username
* the user's login name
* @param password
* the user's password (hashed)
* @param firstname
* the user's first name
* @param lastname
* the user's lastname
* @param userState
* the user's {@link UserState}
* @param roles
* the set of {@link Role}s assigned to this user
* @param locale
* the user's {@link Locale}
* @param propertyMap
* a {@link Map} containing string value pairs of properties for this user
*/
public User(String userId, String username, String password, String firstname, String lastname,
UserState userState, Set<String> roles, Locale locale, Map<String, String> propertyMap) {
if (StringHelper.isEmpty(userId)) {
throw new PrivilegeException("No UserId defined!"); //$NON-NLS-1$
}
if (userState == null) {
throw new PrivilegeException("No userState defined!"); //$NON-NLS-1$
}
if (StringHelper.isEmpty(username)) {
throw new PrivilegeException("No username defined!"); //$NON-NLS-1$
}
if (userState != UserState.SYSTEM) {
if (StringHelper.isEmpty(lastname)) {
throw new PrivilegeException("No lastname defined!"); //$NON-NLS-1$
}
if (StringHelper.isEmpty(firstname)) {
throw new PrivilegeException("No firstname defined!"); //$NON-NLS-1$
}
}
// password may be null, meaning not able to login
// roles may be null, meaning not able to login and must be added later
// locale may be null, meaning use system default
// properties may be null, meaning no properties
this.userId = userId;
this.username = username;
this.password = StringHelper.isEmpty(password) ? null : password;
this.userState = userState;
this.firstname = firstname;
this.lastname = lastname;
if (roles == null)
this.roles = Collections.emptySet();
else
this.roles = Collections.unmodifiableSet(new HashSet<>(roles));
if (locale == null)
this.locale = Locale.getDefault();
else
this.locale = locale;
if (propertyMap == null)
this.propertyMap = Collections.emptyMap();
else
this.propertyMap = Collections.unmodifiableMap(new HashMap<>(propertyMap));
}
/**
* @return the userId
*/
public String getUserId() {
return this.userId;
}
/**
* @return the username
*/
public String getUsername() {
return this.username;
}
/**
* Returns the hashed password for this {@link User}
*
* @return the hashed password for this {@link User}
*/
public String getPassword() {
return this.password;
}
/**
* @return the first name
*/
public String getFirstname() {
return this.firstname;
}
/**
* @return the last name
*/
public String getLastname() {
return this.lastname;
}
/**
* @return the userState
*/
public UserState getUserState() {
return this.userState;
}
/**
* @return the roles
*/
public Set<String> getRoles() {
return this.roles;
}
/**
* Returns true if this user has the specified role
*
* @param role
* the name of the {@link Role} to check for
*
* @return true if the this user has the specified role
*/
public boolean hasRole(String role) {
return this.roles.contains(role);
}
/**
* @return the locale
*/
public Locale getLocale() {
return this.locale;
}
/**
* Returns the property with the given key
*
* @param key
* the key for which the property is to be returned
*
* @return the property with the given key, or null if the property is not defined
*/
public String getProperty(String key) {
return this.propertyMap.get(key);
}
/**
* Returns the {@link Set} of keys of all properties
*
* @return the {@link Set} of keys of all properties
*/
public Set<String> getPropertyKeySet() {
return this.propertyMap.keySet();
}
/**
* Returns the map of properties
*
* @return the map of properties
*/
public Map<String, String> getProperties() {
return this.propertyMap;
}
/**
* @return a {@link UserRep} which is a representation of this object used to serialize and view on clients
*/
public UserRep asUserRep() {
return new UserRep(this.userId, this.username, this.firstname, this.lastname, this.userState,
new HashSet<>(this.roles), this.locale, new HashMap<>(this.propertyMap));
}
/**
* Returns a string representation of this object displaying its concrete type and its values
*
* @see java.lang.Object#toString()
*/
@SuppressWarnings("nls")
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("User [userId=");
builder.append(this.userId);
builder.append(", username=");
builder.append(this.username);
builder.append(", firstname=");
builder.append(this.firstname);
builder.append(", lastname=");
builder.append(this.lastname);
builder.append(", locale=");
builder.append(this.locale);
builder.append(", userState=");
builder.append(this.userState);
builder.append(", roles=");
builder.append(this.roles);
builder.append("]");
return builder.toString();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((this.userId == null) ? 0 : this.userId.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (this.userId == null) {
if (other.userId != null)
return false;
} else if (!this.userId.equals(other.userId))
return false;
return true;
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.policy;
import java.text.MessageFormat;
import ch.eitchnet.privilege.base.PrivilegeException;
import ch.eitchnet.privilege.i18n.PrivilegeMessages;
import ch.eitchnet.privilege.model.IPrivilege;
import ch.eitchnet.privilege.model.PrivilegeContext;
import ch.eitchnet.privilege.model.Restrictable;
import ch.eitchnet.privilege.model.internal.Role;
/**
* This is a simple implementation of {@link PrivilegePolicy} which uses the {@link Restrictable#getPrivilegeName()} to
* see if a given {@link Role} has the privilege required by the value from {@link Restrictable#getPrivilegeValue()}
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class DefaultPrivilege implements PrivilegePolicy {
/**
* The value of {@link Restrictable#getPrivilegeValue()} is used to check if the {@link Role} has this privilege
*
* @see ch.eitchnet.privilege.policy.PrivilegePolicy#validateAction(IPrivilege, Restrictable)
*/
@Override
public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable) {
PrivilegePolicyHelper.preValidate(privilege, restrictable);
// get the value on which the action is to be performed
Object object = restrictable.getPrivilegeValue();
// DefaultPrivilege policy expects the privilege value to be a string
if (!(object instanceof String)) {
String msg = Restrictable.class.getName()
+ PrivilegeMessages.getString("Privilege.illegalArgument.nonstring"); //$NON-NLS-1$
msg = MessageFormat.format(msg, restrictable.getClass().getSimpleName());
throw new PrivilegeException(msg);
}
// if everything is allowed, then no need to carry on
if (privilege.isAllAllowed())
return;
String privilegeValue = (String) object;
PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue);
}
}

View File

@ -0,0 +1,54 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.policy;
import ch.eitchnet.privilege.base.AccessDeniedException;
import ch.eitchnet.privilege.model.IPrivilege;
import ch.eitchnet.privilege.model.PrivilegeContext;
import ch.eitchnet.privilege.model.Restrictable;
import ch.eitchnet.privilege.model.internal.Role;
import ch.eitchnet.privilege.model.internal.User;
/**
* <p>
* {@link PrivilegePolicy} implements logic to determine if a {@link User} which has the given {@link Role} and the
* given {@link IPrivilege} has access to the given {@link Restrictable}
* </p>
*
* <p>
* TODO
* </p>
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public interface PrivilegePolicy {
/**
* Checks if the given {@link Role} and the given {@link IPrivilege} has access to the given {@link Restrictable}
*
* @param context
* the privilege context
* @param privilege
* the {@link IPrivilege} containing the permissions
* @param restrictable
* the {@link Restrictable} to which the user wants access
*
* @throws AccessDeniedException
* if action not allowed
*/
public abstract void validateAction(PrivilegeContext context, IPrivilege privilege, Restrictable restrictable)
throws AccessDeniedException;
}

View File

@ -0,0 +1,80 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.policy;
import java.text.MessageFormat;
import ch.eitchnet.privilege.base.AccessDeniedException;
import ch.eitchnet.privilege.base.PrivilegeException;
import ch.eitchnet.privilege.i18n.PrivilegeMessages;
import ch.eitchnet.privilege.model.IPrivilege;
import ch.eitchnet.privilege.model.PrivilegeContext;
import ch.eitchnet.privilege.model.Restrictable;
import ch.eitchnet.utils.helper.StringHelper;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class PrivilegePolicyHelper {
public static String preValidate(IPrivilege privilege, Restrictable restrictable) {
if (privilege == null)
throw new PrivilegeException(PrivilegeMessages.getString("Privilege.privilegeNull")); //$NON-NLS-1$
if (restrictable == null)
throw new PrivilegeException(PrivilegeMessages.getString("Privilege.restrictableNull")); //$NON-NLS-1$
// get the PrivilegeName
String privilegeName = restrictable.getPrivilegeName();
if (StringHelper.isEmpty(privilegeName)) {
String msg = PrivilegeMessages.getString("Privilege.privilegeNameEmpty"); //$NON-NLS-1$
throw new PrivilegeException(MessageFormat.format(msg, restrictable));
}
// we want the privileges names to match
if (!privilege.getName().equals(privilegeName)) {
throw new PrivilegeException(MessageFormat.format(
PrivilegeMessages.getString("Privilege.illegalArgument.privilegeNameMismatch"), //$NON-NLS-1$
privilege.getName(), privilegeName));
}
return privilegeName;
}
/**
* @param privilege
* @param privilegeValue
*/
public static void checkByAllowDenyValues(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable,
String privilegeValue) {
// first check values not allowed
if (privilege.isDenied(privilegeValue)) {
// then throw access denied
String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.accessdenied.noprivilege"), //$NON-NLS-1$
ctx.getUsername(), privilege.getName(), restrictable.getClass().getName());
throw new AccessDeniedException(msg);
}
// now check values allowed
if (privilege.isAllowed(privilegeValue))
return;
// default is not allowed
String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.accessdenied.noprivilege"), //$NON-NLS-1$
ctx.getUsername(), privilege.getName(), restrictable.getClass().getName());
throw new AccessDeniedException(msg);
}
}

View File

@ -0,0 +1,117 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.policy;
import java.text.MessageFormat;
import ch.eitchnet.privilege.base.PrivilegeException;
import ch.eitchnet.privilege.handler.PrivilegeHandler;
import ch.eitchnet.privilege.i18n.PrivilegeMessages;
import ch.eitchnet.privilege.model.IPrivilege;
import ch.eitchnet.privilege.model.PrivilegeContext;
import ch.eitchnet.privilege.model.Restrictable;
import ch.eitchnet.privilege.model.internal.Role;
import ch.eitchnet.utils.collections.Tuple;
import ch.eitchnet.utils.dbc.DBC;
/**
* This {@link PrivilegePolicy} expects a {@link Tuple} as {@link Restrictable#getPrivilegeValue()}. The Tuple must
* contain {@link Role} as first and second value. Then the policy decides depending on the user specific privileges
* (see {@link PrivilegeHandler}), uses the basic <code>Allow</code> and <code>Deny</code> to detect if the username of
* the certificate is allowed
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class RoleAccessPrivilege implements PrivilegePolicy {
@Override
public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable) {
String privilegeName = PrivilegePolicyHelper.preValidate(privilege, restrictable);
// get the value on which the action is to be performed
Object object = restrictable.getPrivilegeValue();
// if the object is null, then it means the validation is that the privilege must exist
if (object == null)
return;
// RoleAccessPrivilege policy expects the privilege value to be a role
if (!(object instanceof Tuple)) {
String msg = Restrictable.class.getName()
+ PrivilegeMessages.getString("Privilege.illegalArgument.nontuple"); //$NON-NLS-1$
msg = MessageFormat.format(msg, restrictable.getClass().getSimpleName());
throw new PrivilegeException(msg);
}
// if everything is allowed, then no need to carry on
if (privilege.isAllAllowed())
return;
Tuple tuple = (Tuple) object;
// get role name as privilege value
Role oldRole = tuple.getFirst();
Role newRole = tuple.getSecond();
switch (privilegeName) {
case PrivilegeHandler.PRIVILEGE_GET_ROLE: {
DBC.INTERIM.assertNull("For " + privilegeName + " first must be null!", oldRole);
DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newRole);
String privilegeValue = newRole.getName();
PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue);
break;
}
case PrivilegeHandler.PRIVILEGE_ADD_ROLE: {
DBC.INTERIM.assertNull("For " + privilegeName + " first must be null!", oldRole);
DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newRole);
String privilegeValue = newRole.getName();
PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue);
break;
}
case PrivilegeHandler.PRIVILEGE_MODIFY_ROLE: {
DBC.INTERIM.assertNotNull("For " + privilegeName + " first must not be null!", oldRole);
DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newRole);
String privilegeValue = newRole.getName();
DBC.INTERIM.assertEquals("oldRole and newRole names must be the same", oldRole.getName(), privilegeValue);
PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue);
break;
}
case PrivilegeHandler.PRIVILEGE_REMOVE_ROLE: {
DBC.INTERIM.assertNull("For " + privilegeName + " first must be null!", oldRole);
DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newRole);
String privilegeValue = newRole.getName();
PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue);
break;
}
default:
String msg = Restrictable.class.getName()
+ PrivilegeMessages.getString("Privilege.roleAccessPrivilege.unknownPrivilege"); //$NON-NLS-1$
msg = MessageFormat.format(msg, privilegeName);
throw new PrivilegeException(msg);
}
}
}

View File

@ -0,0 +1,190 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.policy;
import java.text.MessageFormat;
import ch.eitchnet.privilege.base.PrivilegeException;
import ch.eitchnet.privilege.handler.PrivilegeHandler;
import ch.eitchnet.privilege.i18n.PrivilegeMessages;
import ch.eitchnet.privilege.model.IPrivilege;
import ch.eitchnet.privilege.model.PrivilegeContext;
import ch.eitchnet.privilege.model.Restrictable;
import ch.eitchnet.privilege.model.internal.User;
import ch.eitchnet.utils.collections.Tuple;
import ch.eitchnet.utils.dbc.DBC;
/**
* This {@link PrivilegePolicy} expects a {@link Tuple} as {@link Restrictable#getPrivilegeValue()} and then depending
* on the user specific privileges (see {@link PrivilegeHandler}), uses the basic <code>Allow</code> and
* <code>Deny</code> to detect if the username of the certificate is allowed
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class UserAccessPrivilege implements PrivilegePolicy {
@Override
public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable) {
String privilegeName = PrivilegePolicyHelper.preValidate(privilege, restrictable);
// get the value on which the action is to be performed
Object object = restrictable.getPrivilegeValue();
// if the object is null, then it means the validation is that the privilege must exist
if (object == null)
return;
// RoleAccessPrivilege policy expects the privilege value to be a role
if (!(object instanceof Tuple)) {
String msg = Restrictable.class.getName()
+ PrivilegeMessages.getString("Privilege.illegalArgument.nontuple"); //$NON-NLS-1$
msg = MessageFormat.format(msg, restrictable.getClass().getSimpleName());
throw new PrivilegeException(msg);
}
// if everything is allowed, then no need to carry on
if (privilege.isAllAllowed())
return;
Tuple tuple = (Tuple) object;
switch (privilegeName) {
case PrivilegeHandler.PRIVILEGE_GET_USER: {
User oldUser = tuple.getFirst();
User newUser = tuple.getSecond();
DBC.INTERIM.assertNull("For " + privilegeName + " first must be null!", oldUser);
DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newUser);
String privilegeValue = newUser.getUsername();
PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue);
break;
}
case PrivilegeHandler.PRIVILEGE_ADD_USER: {
User oldUser = tuple.getFirst();
User newUser = tuple.getSecond();
DBC.INTERIM.assertNull("For " + privilegeName + " first must be null!", oldUser);
DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newUser);
String privilegeValue = newUser.getUsername();
PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue);
break;
}
case PrivilegeHandler.PRIVILEGE_REMOVE_USER: {
User oldUser = tuple.getFirst();
User newUser = tuple.getSecond();
DBC.INTERIM.assertNull("For " + privilegeName + " first must be null!", oldUser);
DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newUser);
String privilegeValue = newUser.getUsername();
PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue);
break;
}
case PrivilegeHandler.PRIVILEGE_MODIFY_USER: {
User oldUser = tuple.getFirst();
User newUser = tuple.getSecond();
DBC.INTERIM.assertNotNull("For " + privilegeName + " first must not be null!", oldUser);
DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newUser);
String privilegeValue = newUser.getUsername();
DBC.INTERIM.assertEquals("oldUser and newUser names must be the same", oldUser.getUsername(),
privilegeValue);
PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue);
break;
}
case PrivilegeHandler.PRIVILEGE_ADD_ROLE_TO_USER: {
User user = tuple.getFirst();
String roleName = tuple.getSecond();
DBC.INTERIM.assertNotNull("For " + privilegeName + " first must not be null!", user);
DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", roleName);
PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, roleName);
break;
}
case PrivilegeHandler.PRIVILEGE_REMOVE_ROLE_FROM_USER: {
User user = tuple.getFirst();
String roleName = tuple.getSecond();
DBC.INTERIM.assertNotNull("For " + privilegeName + " first must not be null!", user);
DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", roleName);
PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, roleName);
break;
}
case PrivilegeHandler.PRIVILEGE_SET_USER_STATE: {
User oldUser = tuple.getFirst();
User newUser = tuple.getSecond();
DBC.INTERIM.assertNotNull("For " + privilegeName + " first must not be null!", oldUser);
DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newUser);
String privilegeValue = newUser.getUserState().name();
PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue);
break;
}
case PrivilegeHandler.PRIVILEGE_SET_USER_LOCALE: {
User oldUser = tuple.getFirst();
User newUser = tuple.getSecond();
DBC.INTERIM.assertNotNull("For " + privilegeName + " first must not be null!", oldUser);
DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newUser);
String privilegeValue = newUser.getUsername();
// user can set their own locale
if (ctx.getUsername().equals(privilegeValue))
return;
PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue);
break;
}
case PrivilegeHandler.PRIVILEGE_SET_USER_PASSWORD: {
User oldUser = tuple.getFirst();
User newUser = tuple.getSecond();
DBC.INTERIM.assertNotNull("For " + privilegeName + " first must not be null!", oldUser);
DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newUser);
String privilegeValue = newUser.getUsername();
// user can set their own password
if (ctx.getUsername().equals(privilegeValue))
return;
PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue);
break;
}
default:
String msg = PrivilegeMessages.getString("Privilege.userAccessPrivilege.unknownPrivilege"); //$NON-NLS-1$
msg = MessageFormat.format(msg, privilegeName, this.getClass().getName());
throw new PrivilegeException(msg);
}
}
}

View File

@ -0,0 +1,115 @@
/*
* Copyright 2015 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.policy;
import java.text.MessageFormat;
import ch.eitchnet.privilege.base.AccessDeniedException;
import ch.eitchnet.privilege.base.PrivilegeException;
import ch.eitchnet.privilege.handler.PrivilegeHandler;
import ch.eitchnet.privilege.i18n.PrivilegeMessages;
import ch.eitchnet.privilege.model.IPrivilege;
import ch.eitchnet.privilege.model.PrivilegeContext;
import ch.eitchnet.privilege.model.Restrictable;
import ch.eitchnet.privilege.model.internal.User;
import ch.eitchnet.utils.collections.Tuple;
import ch.eitchnet.utils.dbc.DBC;
import ch.eitchnet.utils.helper.StringHelper;
/**
* Validates that any access to a privilege User is done only by users in the same organisation
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class UserAccessWithSameOrganisationPrivilege extends UserAccessPrivilege {
private static final String PARAM_ORGANISATION = "organisation";
@Override
public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable) {
String privilegeName = PrivilegePolicyHelper.preValidate(privilege, restrictable);
// get the value on which the action is to be performed
Object object = restrictable.getPrivilegeValue();
// RoleAccessPrivilege policy expects the privilege value to be a role
if (!(object instanceof Tuple)) {
String msg = Restrictable.class.getName()
+ PrivilegeMessages.getString("Privilege.illegalArgument.nontuple"); //$NON-NLS-1$
msg = MessageFormat.format(msg, restrictable.getClass().getSimpleName());
throw new PrivilegeException(msg);
}
// get user organisation
String userOrg = ctx.getCertificate().getProperty(PARAM_ORGANISATION);
if (StringHelper.isEmpty(userOrg)) {
throw new AccessDeniedException("No organisation configured for user " + ctx.getUsername());
}
Tuple tuple = (Tuple) object;
switch (privilegeName) {
case PrivilegeHandler.PRIVILEGE_GET_USER:
case PrivilegeHandler.PRIVILEGE_ADD_USER:
case PrivilegeHandler.PRIVILEGE_MODIFY_USER:
case PrivilegeHandler.PRIVILEGE_REMOVE_USER: {
// make sure old user has same organisation
User oldUser = tuple.getFirst();
if (oldUser != null) {
String oldOrg = oldUser.getProperty(PARAM_ORGANISATION);
if (!userOrg.equals(oldOrg)) {
throw new AccessDeniedException("User " + ctx.getUsername()
+ " may not access users outside of their organisation: " + userOrg + " / " + oldOrg);
}
}
// make sure new user has same organisation
User newUser = tuple.getSecond();
DBC.INTERIM.assertNotNull("For " + privilegeName + " second must not be null!", newUser);
String newdOrg = newUser.getProperty(PARAM_ORGANISATION);
if (!userOrg.equals(newdOrg)) {
throw new AccessDeniedException("User " + ctx.getUsername()
+ " may not access users outside of their organisations: " + userOrg + " / " + newdOrg);
}
break;
}
case PrivilegeHandler.PRIVILEGE_ADD_ROLE_TO_USER:
case PrivilegeHandler.PRIVILEGE_REMOVE_ROLE_FROM_USER: {
User user = tuple.getFirst();
DBC.INTERIM.assertNotNull("For " + privilegeName + " first must not be null!", user);
String org = user.getProperty(PARAM_ORGANISATION);
if (!userOrg.equals(org)) {
throw new AccessDeniedException("User " + ctx.getUsername()
+ " may not access users outside of their organisation: " + userOrg + " / " + org);
}
break;
}
default:
String msg = Restrictable.class.getName()
+ PrivilegeMessages.getString("Privilege.userAccessPrivilege.unknownPrivilege"); //$NON-NLS-1$
msg = MessageFormat.format(msg, privilegeName);
throw new PrivilegeException(msg);
}
// now delegate the rest of the validation to the super class
super.validateAction(ctx, privilege, restrictable);
}
}

View File

@ -0,0 +1,65 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.policy;
import java.text.MessageFormat;
import ch.eitchnet.privilege.base.PrivilegeException;
import ch.eitchnet.privilege.i18n.PrivilegeMessages;
import ch.eitchnet.privilege.model.Certificate;
import ch.eitchnet.privilege.model.IPrivilege;
import ch.eitchnet.privilege.model.PrivilegeContext;
import ch.eitchnet.privilege.model.Restrictable;
/**
* <p>
* This {@link PrivilegePolicy} expects a {@link Certificate} as {@link Restrictable#getPrivilegeValue()} and uses the
* basic <code>Allow</code> and <code>Deny</code> to detect if the username of the certificate is allowed.
* </p>
*
* <p>
* The {@link Certificate} as privilegeValue is not to be confused with the {@link Certificate} of the current user.
* This certificate is of the user to which access is request, i.e. modifying the session of a logged in user.
* </p>
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class UsernameFromCertificatePrivilege implements PrivilegePolicy {
@Override
public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable) {
PrivilegePolicyHelper.preValidate(privilege, restrictable);
// get the value on which the action is to be performed
Object object = restrictable.getPrivilegeValue();
// RoleAccessPrivilege policy expects the privilege value to be a role
if (!(object instanceof Certificate)) {
String msg = Restrictable.class.getName()
+ PrivilegeMessages.getString("Privilege.illegalArgument.noncertificate"); //$NON-NLS-1$
msg = MessageFormat.format(msg, restrictable.getClass().getSimpleName());
throw new PrivilegeException(msg);
}
// if everything is allowed, then no need to carry on
if (privilege.isAllAllowed())
return;
Certificate cert = (Certificate) object;
String privilegeValue = cert.getUsername();
PrivilegePolicyHelper.checkByAllowDenyValues(ctx, privilege, restrictable, privilegeValue);
}
}

View File

@ -0,0 +1,79 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.policy;
import java.text.MessageFormat;
import ch.eitchnet.privilege.base.AccessDeniedException;
import ch.eitchnet.privilege.base.PrivilegeException;
import ch.eitchnet.privilege.i18n.PrivilegeMessages;
import ch.eitchnet.privilege.model.Certificate;
import ch.eitchnet.privilege.model.IPrivilege;
import ch.eitchnet.privilege.model.PrivilegeContext;
import ch.eitchnet.privilege.model.Restrictable;
import ch.eitchnet.utils.helper.StringHelper;
/**
* <p>
* This {@link PrivilegePolicy} expects a {@link Certificate} as {@link Restrictable#getPrivilegeValue()} and uses the
* basic <code>Allow</code> and <code>Deny</code> to detect if the username of the certificate is allowed.
* </p>
*
* <p>
* The {@link Certificate} as privilegeValue is not to be confused with the {@link Certificate} of the current user.
* This certificate is of the user to which access is request, i.e. modifying the session of a logged in user.
* </p>
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class UsernameFromCertificateWithSameOrganisationPrivilege extends UsernameFromCertificatePrivilege {
private static final String PARAM_ORGANISATION = "organisation";
@Override
public void validateAction(PrivilegeContext ctx, IPrivilege privilege, Restrictable restrictable) {
PrivilegePolicyHelper.preValidate(privilege, restrictable);
// get the value on which the action is to be performed
Object object = restrictable.getPrivilegeValue();
// RoleAccessPrivilege policy expects the privilege value to be a role
if (!(object instanceof Certificate)) {
String msg = Restrictable.class.getName()
+ PrivilegeMessages.getString("Privilege.illegalArgument.noncertificate"); //$NON-NLS-1$
msg = MessageFormat.format(msg, restrictable.getClass().getSimpleName());
throw new PrivilegeException(msg);
}
// get object
Certificate cert = (Certificate) object;
// get user organisation
String userOrg = ctx.getCertificate().getProperty(PARAM_ORGANISATION);
if (StringHelper.isEmpty(userOrg)) {
throw new AccessDeniedException("No organisation configured for user " + ctx.getUsername());
}
// assert same organisation
String org = cert.getProperty(PARAM_ORGANISATION);
if (!userOrg.equals(org)) {
throw new AccessDeniedException("User " + ctx.getUsername()
+ " may not access users outside of their organisation: " + userOrg + " / " + org);
}
// now delegate the rest of the validation to the super class
super.validateAction(ctx, privilege, restrictable);
}
}

View File

@ -0,0 +1,79 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.xml;
import java.io.OutputStream;
import java.util.List;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import ch.eitchnet.privilege.helper.XmlConstants;
import ch.eitchnet.privilege.model.Certificate;
import ch.eitchnet.utils.helper.XmlHelper;
import ch.eitchnet.utils.iso8601.ISO8601FormatFactory;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class CertificateStubsDomWriter {
private List<Certificate> certificates;
private OutputStream outputStream;
public CertificateStubsDomWriter(List<Certificate> certificates, OutputStream outputStream) {
this.certificates = certificates;
this.outputStream = outputStream;
}
public void write() {
// create document root
Document doc = XmlHelper.createDocument();
Element rootElement = doc.createElement(XmlConstants.XML_ROOT_CERTIFICATES);
doc.appendChild(rootElement);
this.certificates.stream().sorted((c1, c2) -> c1.getSessionId().compareTo(c2.getSessionId())).forEach(cert -> {
// create the certificate element
Element certElement = doc.createElement(XmlConstants.XML_CERTIFICATE);
rootElement.appendChild(certElement);
// sessionId;
certElement.setAttribute(XmlConstants.XML_ATTR_SESSION_ID, cert.getSessionId());
// username;
certElement.setAttribute(XmlConstants.XML_ATTR_USERNAME, cert.getUsername());
// authToken;
certElement.setAttribute(XmlConstants.XML_ATTR_AUTH_TOKEN, cert.getAuthToken());
// locale;
certElement.setAttribute(XmlConstants.XML_ATTR_LOCALE, cert.getLocale().toString());
// loginTime;
certElement.setAttribute(XmlConstants.XML_ATTR_LOGIN_TIME,
ISO8601FormatFactory.getInstance().formatDate(cert.getLoginTime()));
// lastAccess;
certElement.setAttribute(XmlConstants.XML_ATTR_LAST_ACCESS,
ISO8601FormatFactory.getInstance().formatDate(cert.getLastAccess()));
});
// write the container file to disk
XmlHelper.writeDocument(doc, this.outputStream);
}
}

View File

@ -0,0 +1,114 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.xml;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import ch.eitchnet.privilege.base.PrivilegeException;
import ch.eitchnet.privilege.helper.XmlConstants;
import ch.eitchnet.utils.dbc.DBC;
import ch.eitchnet.utils.helper.XmlHelper;
import ch.eitchnet.utils.iso8601.ISO8601FormatFactory;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class CertificateStubsSaxReader extends DefaultHandler {
private InputStream inputStream;
private List<CertificateStub> stubs;
public CertificateStubsSaxReader(InputStream inputStream) {
this.inputStream = inputStream;
}
public List<CertificateStub> read() {
this.stubs = new ArrayList<>();
XmlHelper.parseDocument(this.inputStream, this);
return stubs;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
switch (qName) {
case XmlConstants.XML_ROOT_CERTIFICATES:
break;
case XmlConstants.XML_CERTIFICATE:
CertificateStub stub = new CertificateStub();
stub.sessionId = attributes.getValue(XmlConstants.XML_ATTR_SESSION_ID);
stub.username = attributes.getValue(XmlConstants.XML_ATTR_USERNAME);
stub.authToken = attributes.getValue(XmlConstants.XML_ATTR_AUTH_TOKEN);
stub.locale = new Locale(attributes.getValue(XmlConstants.XML_ATTR_LOCALE));
stub.loginTime = ISO8601FormatFactory.getInstance()
.parseDate(attributes.getValue(XmlConstants.XML_ATTR_LOGIN_TIME));
stub.lastAccess = ISO8601FormatFactory.getInstance()
.parseDate(attributes.getValue(XmlConstants.XML_ATTR_LAST_ACCESS));
DBC.INTERIM.assertNotEmpty("sessionId missing on sessions data!", stub.sessionId);
DBC.INTERIM.assertNotEmpty("username missing on sessions data!", stub.username);
DBC.INTERIM.assertNotEmpty("authToken missing on sessions data!", stub.authToken);
this.stubs.add(stub);
break;
default:
throw new PrivilegeException("Unhandled tag " + qName);
}
}
public class CertificateStub {
private String sessionId;
private String username;
private String authToken;
private Locale locale;
private Date loginTime;
private Date lastAccess;
public String getSessionId() {
return sessionId;
}
public String getUsername() {
return username;
}
public String getAuthToken() {
return authToken;
}
public Locale getLocale() {
return locale;
}
public Date getLoginTime() {
return loginTime;
}
public Date getLastAccess() {
return lastAccess;
}
}
}

View File

@ -0,0 +1,31 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.xml;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
// TODO write JavaDoc...
public interface ElementParser {
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException;
public void characters(char[] ch, int start, int length) throws SAXException;
public void endElement(String uri, String localName, String qName) throws SAXException;
public void notifyChild(ElementParser child);
}

View File

@ -0,0 +1,42 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.xml;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
public abstract class ElementParserAdapter implements ElementParser {
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
// empty implementation
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
// empty implementation
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
// empty implementation
}
@Override
public void notifyChild(ElementParser child) {
// empty implementation
}
}

View File

@ -0,0 +1,115 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.xml;
import java.io.File;
import java.util.Map.Entry;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import ch.eitchnet.privilege.helper.XmlConstants;
import ch.eitchnet.privilege.model.internal.PrivilegeContainerModel;
import ch.eitchnet.privilege.policy.PrivilegePolicy;
import ch.eitchnet.utils.helper.XmlHelper;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*
*/
public class PrivilegeConfigDomWriter {
private final PrivilegeContainerModel containerModel;
private final File configFile;
/**
*
*/
public PrivilegeConfigDomWriter(PrivilegeContainerModel containerModel, File configFile) {
this.containerModel = containerModel;
this.configFile = configFile;
}
/**
*
*/
public void write() {
// create document root
Document doc = XmlHelper.createDocument();
Element rootElement = doc.createElement(XmlConstants.XML_ROOT_PRIVILEGE);
doc.appendChild(rootElement);
Element containerElement = doc.createElement(XmlConstants.XML_CONTAINER);
rootElement.appendChild(containerElement);
Element parameterElement;
Element parametersElement;
// Parameters
parametersElement = doc.createElement(XmlConstants.XML_PARAMETERS);
containerElement.appendChild(parametersElement);
for (Entry<String, String> entry : this.containerModel.getParameterMap().entrySet()) {
parameterElement = doc.createElement(XmlConstants.XML_PARAMETER);
parameterElement.setAttribute(XmlConstants.XML_ATTR_NAME, entry.getKey());
parameterElement.setAttribute(XmlConstants.XML_ATTR_VALUE, entry.getValue());
parametersElement.appendChild(parameterElement);
}
// create EncryptionHandler
Element encryptionHandlerElem = doc.createElement(XmlConstants.XML_HANDLER_ENCRYPTION);
containerElement.appendChild(encryptionHandlerElem);
encryptionHandlerElem.setAttribute(XmlConstants.XML_ATTR_CLASS,
this.containerModel.getEncryptionHandlerClassName());
// Parameters
parametersElement = doc.createElement(XmlConstants.XML_PARAMETERS);
encryptionHandlerElem.appendChild(parametersElement);
for (Entry<String, String> entry : this.containerModel.getEncryptionHandlerParameterMap().entrySet()) {
parameterElement = doc.createElement(XmlConstants.XML_PARAMETER);
parameterElement.setAttribute(XmlConstants.XML_ATTR_NAME, entry.getKey());
parameterElement.setAttribute(XmlConstants.XML_ATTR_VALUE, entry.getValue());
parametersElement.appendChild(parameterElement);
}
// create PersistenceHandler
Element persistenceHandlerElem = doc.createElement(XmlConstants.XML_HANDLER_PERSISTENCE);
containerElement.appendChild(persistenceHandlerElem);
persistenceHandlerElem.setAttribute(XmlConstants.XML_ATTR_CLASS,
this.containerModel.getPersistenceHandlerClassName());
// Parameters
parametersElement = doc.createElement(XmlConstants.XML_PARAMETERS);
persistenceHandlerElem.appendChild(parametersElement);
for (Entry<String, String> entry : this.containerModel.getPersistenceHandlerParameterMap().entrySet()) {
parameterElement = doc.createElement(XmlConstants.XML_PARAMETER);
parameterElement.setAttribute(XmlConstants.XML_ATTR_NAME, entry.getKey());
parameterElement.setAttribute(XmlConstants.XML_ATTR_VALUE, entry.getValue());
parametersElement.appendChild(parameterElement);
}
// Policies
Element policiesElem = doc.createElement(XmlConstants.XML_POLICIES);
rootElement.appendChild(policiesElem);
for (Entry<String, Class<PrivilegePolicy>> entry : this.containerModel.getPolicies().entrySet()) {
Element policyElem = doc.createElement(XmlConstants.XML_POLICY);
policyElem.setAttribute(XmlConstants.XML_ATTR_NAME, entry.getKey());
policyElem.setAttribute(XmlConstants.XML_ATTR_CLASS, entry.getValue().getName());
policiesElem.appendChild(policyElem);
}
// write the container file to disk
XmlHelper.writeDocument(doc, this.configFile);
}
}

View File

@ -0,0 +1,181 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.xml;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashMap;
import java.util.Map;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import ch.eitchnet.privilege.helper.XmlConstants;
import ch.eitchnet.privilege.model.internal.PrivilegeContainerModel;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class PrivilegeConfigSaxReader extends DefaultHandler {
private Deque<ElementParser> buildersStack = new ArrayDeque<>();
private PrivilegeContainerModel containerModel;
public PrivilegeConfigSaxReader(PrivilegeContainerModel containerModel) {
this.containerModel = containerModel;
}
public PrivilegeContainerModel getContainerModel() {
return this.containerModel;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (qName.equals(XmlConstants.XML_CONTAINER)) {
this.buildersStack.push(new ContainerParser());
} else if (qName.equals(XmlConstants.XML_PARAMETERS)) {
this.buildersStack.push(new ParametersParser());
} else if (qName.equals(XmlConstants.XML_POLICIES)) {
this.buildersStack.push(new PoliciesParser());
}
if (!this.buildersStack.isEmpty())
this.buildersStack.peek().startElement(uri, localName, qName, attributes);
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if (!this.buildersStack.isEmpty())
this.buildersStack.peek().characters(ch, start, length);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (!this.buildersStack.isEmpty())
this.buildersStack.peek().endElement(uri, localName, qName);
ElementParser elementParser = null;
if (qName.equals(XmlConstants.XML_CONTAINER)) {
elementParser = this.buildersStack.pop();
} else if (qName.equals(XmlConstants.XML_PARAMETERS)) {
elementParser = this.buildersStack.pop();
} else if (qName.equals(XmlConstants.XML_POLICIES)) {
elementParser = this.buildersStack.pop();
}
if (!this.buildersStack.isEmpty() && elementParser != null)
this.buildersStack.peek().notifyChild(elementParser);
}
public class ContainerParser extends ElementParserAdapter {
// <Container>
// <Parameters>
// <!-- parameters for the container itself -->
// <Parameter name="autoPersistOnPasswordChange" value="true" />
// </Parameters>
// <EncryptionHandler class="ch.eitchnet.privilege.handler.DefaultEncryptionHandler">
// <Parameters>
// <Parameter name="hashAlgorithm" value="SHA-256" />
// </Parameters>
// </EncryptionHandler>
// <PersistenceHandler class="ch.eitchnet.privilege.handler.XmlPersistenceHandler">
// <Parameters>
// <Parameter name="basePath" value="./target/test" />
// <Parameter name="modelXmlFile" value="PrivilegeModel.xml" />
// </Parameters>
// </PersistenceHandler>
// </Container>
private String currentElement;
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
if (qName.equals(XmlConstants.XML_CONTAINER)) {
this.currentElement = qName;
} else if (qName.equals(XmlConstants.XML_HANDLER_ENCRYPTION)) {
this.currentElement = qName;
String className = attributes.getValue(XmlConstants.XML_ATTR_CLASS);
getContainerModel().setEncryptionHandlerClassName(className);
} else if (qName.equals(XmlConstants.XML_HANDLER_PERSISTENCE)) {
this.currentElement = qName;
String className = attributes.getValue(XmlConstants.XML_ATTR_CLASS);
getContainerModel().setPersistenceHandlerClassName(className);
}
}
@Override
public void notifyChild(ElementParser child) {
if (!(child instanceof ParametersParser))
return;
ParametersParser parametersChild = (ParametersParser) child;
if (this.currentElement.equals(XmlConstants.XML_CONTAINER)) {
getContainerModel().setParameterMap(parametersChild.getParameterMap());
} else if (this.currentElement.equals(XmlConstants.XML_HANDLER_ENCRYPTION)) {
getContainerModel().setEncryptionHandlerParameterMap(parametersChild.getParameterMap());
} else if (this.currentElement.equals(XmlConstants.XML_HANDLER_PERSISTENCE)) {
getContainerModel().setPersistenceHandlerParameterMap(parametersChild.getParameterMap());
}
}
}
class ParametersParser extends ElementParserAdapter {
// <Parameter name="autoPersistOnPasswordChange" value="true" />
private Map<String, String> parameterMap = new HashMap<>();
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
if (qName.equals(XmlConstants.XML_PARAMETER)) {
String key = attributes.getValue(XmlConstants.XML_ATTR_NAME);
String value = attributes.getValue(XmlConstants.XML_ATTR_VALUE);
this.parameterMap.put(key, value);
}
}
/**
* @return the parameterMap
*/
public Map<String, String> getParameterMap() {
return this.parameterMap;
}
}
class PoliciesParser extends ElementParserAdapter {
// <Policy name="DefaultPrivilege" class="ch.eitchnet.privilege.policy.DefaultPrivilege" />
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
if (qName.equals(XmlConstants.XML_POLICY)) {
String policyName = attributes.getValue(XmlConstants.XML_ATTR_NAME);
String policyClassName = attributes.getValue(XmlConstants.XML_ATTR_CLASS);
getContainerModel().addPolicy(policyName, policyClassName);
}
}
}
}

View File

@ -0,0 +1,98 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.xml;
import java.io.File;
import java.util.List;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import ch.eitchnet.privilege.helper.XmlConstants;
import ch.eitchnet.privilege.model.IPrivilege;
import ch.eitchnet.privilege.model.internal.Role;
import ch.eitchnet.utils.helper.XmlHelper;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class PrivilegeRolesDomWriter {
private List<Role> roles;
private File modelFile;
/**
* @param users
* @param roles
* @param modelFile
*/
public PrivilegeRolesDomWriter(List<Role> roles, File modelFile) {
this.roles = roles;
this.modelFile = modelFile;
}
public void write() {
// create document root
Document doc = XmlHelper.createDocument();
Element rootElement = doc.createElement(XmlConstants.XML_ROLES);
doc.appendChild(rootElement);
this.roles.stream().sorted((r1, r2) -> r1.getName().compareTo(r2.getName())).forEach(role -> {
// create the role element
Element roleElement = doc.createElement(XmlConstants.XML_ROLE);
rootElement.appendChild(roleElement);
roleElement.setAttribute(XmlConstants.XML_ATTR_NAME, role.getName());
for (String privilegeName : role.getPrivilegeNames()) {
IPrivilege privilege = role.getPrivilege(privilegeName);
// create the privilege element
Element privilegeElement = doc.createElement(XmlConstants.XML_PRIVILEGE);
roleElement.appendChild(privilegeElement);
privilegeElement.setAttribute(XmlConstants.XML_ATTR_NAME, privilege.getName());
privilegeElement.setAttribute(XmlConstants.XML_ATTR_POLICY, privilege.getPolicy());
// add the all allowed element
if (privilege.isAllAllowed()) {
Element allAllowedElement = doc.createElement(XmlConstants.XML_ALL_ALLOWED);
allAllowedElement.setTextContent(Boolean.toString(privilege.isAllAllowed()));
privilegeElement.appendChild(allAllowedElement);
}
// add all the deny values
for (String denyValue : privilege.getDenyList()) {
Element denyValueElement = doc.createElement(XmlConstants.XML_DENY);
denyValueElement.setTextContent(denyValue);
privilegeElement.appendChild(denyValueElement);
}
// add all the allow values
for (String allowValue : privilege.getAllowList()) {
Element allowValueElement = doc.createElement(XmlConstants.XML_ALLOW);
allowValueElement.setTextContent(allowValue);
privilegeElement.appendChild(allowValueElement);
}
}
});
// write the container file to disk
XmlHelper.writeDocument(doc, this.modelFile);
}
}

View File

@ -0,0 +1,220 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.xml;
import java.text.MessageFormat;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import ch.eitchnet.privilege.helper.XmlConstants;
import ch.eitchnet.privilege.model.IPrivilege;
import ch.eitchnet.privilege.model.internal.PrivilegeImpl;
import ch.eitchnet.privilege.model.internal.Role;
import ch.eitchnet.utils.helper.StringHelper;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class PrivilegeRolesSaxReader extends DefaultHandler {
protected static final Logger logger = LoggerFactory.getLogger(PrivilegeRolesSaxReader.class);
private Deque<ElementParser> buildersStack = new ArrayDeque<>();
private List<Role> roles;
public PrivilegeRolesSaxReader() {
this.roles = new ArrayList<>();
}
public List<Role> getRoles() {
return this.roles;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (qName.equals(XmlConstants.XML_ROLE)) {
this.buildersStack.push(new RoleParser());
} else if (qName.equals(XmlConstants.XML_PROPERTIES)) {
this.buildersStack.push(new PropertyParser());
}
if (!this.buildersStack.isEmpty())
this.buildersStack.peek().startElement(uri, localName, qName, attributes);
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if (!this.buildersStack.isEmpty())
this.buildersStack.peek().characters(ch, start, length);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (!this.buildersStack.isEmpty())
this.buildersStack.peek().endElement(uri, localName, qName);
ElementParser elementParser = null;
if (qName.equals(XmlConstants.XML_ROLE)) {
elementParser = this.buildersStack.pop();
} else if (qName.equals(XmlConstants.XML_PROPERTIES)) {
elementParser = this.buildersStack.pop();
}
if (!this.buildersStack.isEmpty() && elementParser != null)
this.buildersStack.peek().notifyChild(elementParser);
}
// <Role name="AppUser">
// <Privilege name="ch.eitchnet.privilege.test.model.TestRestrictable">
// <AllAllowed>true</AllAllowed>
// </Privilege>
// </Role>
// <Role name="system_admin_privileges">
// <Privilege name="ch.eitchnet.privilege.test.model.TestSystemUserAction">
// <AllAllowed>true</AllAllowed>
// </Privilege>
// <Privilege name="ch.eitchnet.privilege.test.model.TestSystemRestrictable">
// <AllAllowed>true</AllAllowed>
// </Privilege>
// </Role>
public class RoleParser extends ElementParserAdapter {
private StringBuilder text;
private String roleName;
private String privilegeName;
private String privilegePolicy;
private boolean allAllowed;
private Set<String> denyList;
private Set<String> allowList;
private Map<String, IPrivilege> privileges;
public RoleParser() {
init();
}
private void init() {
this.privileges = new HashMap<>();
this.text = null;
this.roleName = null;
this.privilegeName = null;
this.privilegePolicy = null;
this.allAllowed = false;
this.denyList = new HashSet<>();
this.allowList = new HashSet<>();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
this.text = new StringBuilder();
if (qName.equals(XmlConstants.XML_ROLE)) {
this.roleName = attributes.getValue(XmlConstants.XML_ATTR_NAME);
} else if (qName.equals(XmlConstants.XML_PRIVILEGE)) {
this.privilegeName = attributes.getValue(XmlConstants.XML_ATTR_NAME);
this.privilegePolicy = attributes.getValue(XmlConstants.XML_ATTR_POLICY);
} else if (qName.equals(XmlConstants.XML_ALLOW) || qName.equals(XmlConstants.XML_DENY)
|| qName.equals(XmlConstants.XML_ALL_ALLOWED)) {
// no-op
} else {
throw new IllegalArgumentException("Unhandled tag " + qName);
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if (this.text != null)
this.text.append(ch, start, length);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equals(XmlConstants.XML_ALL_ALLOWED)) {
this.allAllowed = StringHelper.parseBoolean(this.text.toString().trim());
} else if (qName.equals(XmlConstants.XML_ALLOW)) {
this.allowList.add(this.text.toString().trim());
} else if (qName.equals(XmlConstants.XML_DENY)) {
this.denyList.add(this.text.toString().trim());
} else if (qName.equals(XmlConstants.XML_PRIVILEGE)) {
IPrivilege privilege = new PrivilegeImpl(this.privilegeName, this.privilegePolicy, this.allAllowed,
this.denyList, this.allowList);
this.privileges.put(this.privilegeName, privilege);
this.privilegeName = null;
this.privilegePolicy = null;
this.allAllowed = false;
this.denyList = new HashSet<>();
this.allowList = new HashSet<>();
} else if (qName.equals(XmlConstants.XML_ROLE)) {
Role role = new Role(this.roleName, this.privileges);
getRoles().add(role);
logger.info(MessageFormat.format("New Role: {0}", role)); //$NON-NLS-1$
init();
}
}
}
class PropertyParser extends ElementParserAdapter {
// <Property name="organizationalUnit" value="Development" />
public Map<String, String> parameterMap = new HashMap<>();
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
if (qName.equals(XmlConstants.XML_PROPERTY)) {
String key = attributes.getValue(XmlConstants.XML_ATTR_NAME);
String value = attributes.getValue(XmlConstants.XML_ATTR_VALUE);
this.parameterMap.put(key, value);
} else if (qName.equals(XmlConstants.XML_PROPERTIES)) {
// NO-OP
} else {
throw new IllegalArgumentException("Unhandled tag " + qName);
}
}
public Map<String, String> getParameterMap() {
return this.parameterMap;
}
}
}

View File

@ -0,0 +1,114 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.xml;
import java.io.File;
import java.util.List;
import java.util.Map.Entry;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import ch.eitchnet.privilege.helper.XmlConstants;
import ch.eitchnet.privilege.model.internal.User;
import ch.eitchnet.utils.helper.StringHelper;
import ch.eitchnet.utils.helper.XmlHelper;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class PrivilegeUsersDomWriter {
private List<User> users;
private File modelFile;
/**
* @param users
* @param modelFile
*/
public PrivilegeUsersDomWriter(List<User> users, File modelFile) {
this.users = users;
this.modelFile = modelFile;
}
public void write() {
// create document root
Document doc = XmlHelper.createDocument();
Element rootElement = doc.createElement(XmlConstants.XML_USERS);
doc.appendChild(rootElement);
this.users.stream().sorted((u1, u2) -> u1.getUserId().compareTo(u2.getUserId())).forEach(user -> {
// create the user element
Element userElement = doc.createElement(XmlConstants.XML_USER);
rootElement.appendChild(userElement);
userElement.setAttribute(XmlConstants.XML_ATTR_USER_ID, user.getUserId());
userElement.setAttribute(XmlConstants.XML_ATTR_USERNAME, user.getUsername());
if (StringHelper.isNotEmpty(user.getPassword()))
userElement.setAttribute(XmlConstants.XML_ATTR_PASSWORD, user.getPassword());
// add first name element
if (StringHelper.isNotEmpty(user.getFirstname())) {
Element firstnameElement = doc.createElement(XmlConstants.XML_FIRSTNAME);
firstnameElement.setTextContent(user.getFirstname());
userElement.appendChild(firstnameElement);
}
// add last name element
if (StringHelper.isNotEmpty(user.getLastname())) {
Element lastnameElement = doc.createElement(XmlConstants.XML_LASTNAME);
lastnameElement.setTextContent(user.getLastname());
userElement.appendChild(lastnameElement);
}
// add state element
Element stateElement = doc.createElement(XmlConstants.XML_STATE);
stateElement.setTextContent(user.getUserState().toString());
userElement.appendChild(stateElement);
// add locale element
Element localeElement = doc.createElement(XmlConstants.XML_LOCALE);
localeElement.setTextContent(user.getLocale().toString());
userElement.appendChild(localeElement);
// add all the role elements
Element rolesElement = doc.createElement(XmlConstants.XML_ROLES);
userElement.appendChild(rolesElement);
for (String roleName : user.getRoles()) {
Element roleElement = doc.createElement(XmlConstants.XML_ROLE);
roleElement.setTextContent(roleName);
rolesElement.appendChild(roleElement);
}
// add the parameters
if (!user.getProperties().isEmpty()) {
Element parametersElement = doc.createElement(XmlConstants.XML_PROPERTIES);
userElement.appendChild(parametersElement);
for (Entry<String, String> entry : user.getProperties().entrySet()) {
Element paramElement = doc.createElement(XmlConstants.XML_PROPERTY);
paramElement.setAttribute(XmlConstants.XML_ATTR_NAME, entry.getKey());
paramElement.setAttribute(XmlConstants.XML_ATTR_VALUE, entry.getValue());
parametersElement.appendChild(paramElement);
}
}
});
// write the container file to disk
XmlHelper.writeDocument(doc, this.modelFile);
}
}

View File

@ -0,0 +1,209 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.xml;
import java.text.MessageFormat;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import ch.eitchnet.privilege.helper.XmlConstants;
import ch.eitchnet.privilege.model.UserState;
import ch.eitchnet.privilege.model.internal.User;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class PrivilegeUsersSaxReader extends DefaultHandler {
protected static final Logger logger = LoggerFactory.getLogger(PrivilegeUsersSaxReader.class);
private Deque<ElementParser> buildersStack = new ArrayDeque<>();
private List<User> users;
public PrivilegeUsersSaxReader() {
this.users = new ArrayList<>();
}
/**
* @return the users
*/
public List<User> getUsers() {
return this.users;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (qName.equals(XmlConstants.XML_USER)) {
this.buildersStack.push(new UserParser());
} else if (qName.equals(XmlConstants.XML_PROPERTIES)) {
this.buildersStack.push(new PropertyParser());
}
if (!this.buildersStack.isEmpty())
this.buildersStack.peek().startElement(uri, localName, qName, attributes);
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if (!this.buildersStack.isEmpty())
this.buildersStack.peek().characters(ch, start, length);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (!this.buildersStack.isEmpty())
this.buildersStack.peek().endElement(uri, localName, qName);
ElementParser elementParser = null;
if (qName.equals(XmlConstants.XML_USER)) {
elementParser = this.buildersStack.pop();
} else if (qName.equals(XmlConstants.XML_PROPERTIES)) {
elementParser = this.buildersStack.pop();
}
if (!this.buildersStack.isEmpty() && elementParser != null)
this.buildersStack.peek().notifyChild(elementParser);
}
// <User userId="1" username="admin" password="8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918">
// <Firstname>Application</Firstname>
// <Lastname>Administrator</Lastname>
// <State>ENABLED</State>
// <Locale>en_GB</Locale>
// <Roles>
// <Role>PrivilegeAdmin</Role>
// <Role>AppUser</Role>
// </Roles>
// <Properties>
// <Property name="organization" value="eitchnet.ch" />
// <Property name="organizationalUnit" value="Development" />
// </Properties>
// </User>
public class UserParser extends ElementParserAdapter {
StringBuilder text;
String userId;
String username;
String password;
String firstName;
String lastname;
UserState userState;
Locale locale;
Set<String> userRoles;
Map<String, String> parameters;
public UserParser() {
this.userRoles = new HashSet<>();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
this.text = new StringBuilder();
if (qName.equals(XmlConstants.XML_USER)) {
this.userId = attributes.getValue(XmlConstants.XML_ATTR_USER_ID);
this.username = attributes.getValue(XmlConstants.XML_ATTR_USERNAME);
this.password = attributes.getValue(XmlConstants.XML_ATTR_PASSWORD);
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
this.text.append(ch, start, length);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equals(XmlConstants.XML_FIRSTNAME)) {
this.firstName = this.text.toString().trim();
} else if (qName.equals(XmlConstants.XML_LASTNAME)) {
this.lastname = this.text.toString().trim();
} else if (qName.equals(XmlConstants.XML_STATE)) {
this.userState = UserState.valueOf(this.text.toString().trim());
} else if (qName.equals(XmlConstants.XML_LOCALE)) {
this.locale = new Locale(this.text.toString().trim());
} else if (qName.equals(XmlConstants.XML_ROLE)) {
this.userRoles.add(this.text.toString().trim());
} else if (qName.equals(XmlConstants.XML_ROLES)) {
// NO-OP
} else if (qName.equals(XmlConstants.XML_PARAMETER)) {
// NO-OP
} else if (qName.equals(XmlConstants.XML_PARAMETERS)) {
// NO-OP
} else if (qName.equals(XmlConstants.XML_USER)) {
User user = new User(this.userId, this.username, this.password, this.firstName, this.lastname,
this.userState, this.userRoles, this.locale, this.parameters);
logger.info(MessageFormat.format("New User: {0}", user)); //$NON-NLS-1$
getUsers().add(user);
} else {
throw new IllegalArgumentException("Unhandled tag " + qName);
}
}
@Override
public void notifyChild(ElementParser child) {
if (child instanceof PropertyParser) {
this.parameters = ((PropertyParser) child).parameterMap;
}
}
}
class PropertyParser extends ElementParserAdapter {
// <Property name="organizationalUnit" value="Development" />
public Map<String, String> parameterMap = new HashMap<>();
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
if (qName.equals(XmlConstants.XML_PROPERTY)) {
String key = attributes.getValue(XmlConstants.XML_ATTR_NAME);
String value = attributes.getValue(XmlConstants.XML_ATTR_VALUE);
this.parameterMap.put(key, value);
} else if (qName.equals(XmlConstants.XML_PROPERTIES)) {
// NO-OP
} else {
throw new IllegalArgumentException("Unhandled tag " + qName);
}
}
public Map<String, String> getParameterMap() {
return this.parameterMap;
}
}
}

View File

@ -0,0 +1,83 @@
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.eitchnet.ch/dev/privilege/Privilege"
xmlns:pr="http://www.eitchnet.ch/dev/privilege/Privilege" elementFormDefault="qualified">
<element name="Privilege">
<annotation>
<documentation>
Copyright 2013 Robert von Burg &lt;eitch@eitchnet.ch&gt;
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.
</documentation>
</annotation>
<complexType>
<sequence>
<element name="Container" minOccurs="1" maxOccurs="1">
<complexType>
<sequence>
<element name="Parameters" type="pr:Parameters" minOccurs="1" maxOccurs="1" />
<element name="EncryptionHandler" type="pr:EncryptionHandler" minOccurs="1" maxOccurs="1" />
<element name="PersistenceHandler" type="pr:PersistenceHandler" minOccurs="1" maxOccurs="1" />
</sequence>
</complexType>
</element>
<element name="Policies" type="pr:Policies" minOccurs="1" maxOccurs="1" />
</sequence>
</complexType>
</element>
<complexType name="Parameters">
<sequence>
<element name="Parameter" minOccurs="0" maxOccurs="unbounded">
<complexType>
<simpleContent>
<extension base="string">
<attribute type="string" name="name" use="required" />
<attribute type="string" name="value" use="required" />
</extension>
</simpleContent>
</complexType>
</element>
</sequence>
</complexType>
<complexType name="EncryptionHandler">
<sequence>
<element name="Parameters" type="pr:Parameters" minOccurs="0" maxOccurs="1" />
</sequence>
<attribute type="string" name="class" use="required" />
</complexType>
<complexType name="PersistenceHandler">
<sequence>
<element name="Parameters" type="pr:Parameters" minOccurs="0" maxOccurs="1" />
</sequence>
<attribute type="string" name="class" use="required" />
</complexType>
<complexType name="Policies">
<sequence>
<element name="Policy" minOccurs="0" maxOccurs="1">
<complexType>
<simpleContent>
<extension base="string">
<attribute type="string" name="name" use="required" />
<attribute type="string" name="class" use="required" />
</extension>
</simpleContent>
</complexType>
</element>
</sequence>
</complexType>
</schema>

View File

@ -0,0 +1,14 @@
Privilege.accessdenied.noprivilege=User {0} does not have the privilege {1} needed for Restrictable {2}
Privilege.illegalArgument.nonstring=\ {0} has returned a non-string privilege value\!
Privilege.illegalArgument.nonrole=\ {0} did not return a Role privilege value\!
Privilege.illegalArgument.noncertificate=\ {0} did not return a Certificate privilege value\!
Privilege.illegalArgument.nonuser=\ {0} did not return a User privilege value\!
Privilege.illegalArgument.privilegeNameMismatch=The passed privilege has the name {0} but the restrictable is referencing privilege {1}
Privilege.illegalArgument.nontuple=\ {0} did not return a Tuple privilege value\!
Privilege.privilegeNameEmpty=The PrivilegeName for the Restrictable is null or empty: {0}
Privilege.privilegeNull=Privilege may not be null\!
Privilege.restrictableNull=Restrictable may not be null\!
Privilege.noprivilege=No Privilege exists with name {0}
Privilege.noprivilege.user=User {0} does not have the privilege {1}
Privilege.roleAccessPrivilege.unknownPrivilege=Unhandled privilege {0} for policy {1}
Privilege.userAccessPrivilege.unknownPrivilege=Unhandled privilege {0} for policy {1}

View File

@ -0,0 +1,98 @@
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.eitchnet.ch/dev/privilege/PrivilegeModel"
xmlns:pr="http://www.eitchnet.ch/dev/privilege/PrivilegeModel" elementFormDefault="qualified">
<element name="UsersAndRoles">
<annotation>
<documentation>
Copyright 2013 Robert von Burg &lt;eitch@eitchnet.ch&gt;
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.
</documentation>
</annotation>
<complexType>
<sequence>
<element name="Users">
<complexType>
<sequence>
<element name="User" type="pr:User" minOccurs="0" maxOccurs="unbounded" />
</sequence>
</complexType>
</element>
<element name="Roles">
<complexType>
<sequence>
<element name="Role" type="pr:Role" minOccurs="0" maxOccurs="unbounded" />
</sequence>
</complexType>
</element>
</sequence>
</complexType>
</element>
<complexType name="User">
<sequence>
<element type="string" name="Firstname" minOccurs="1" maxOccurs="1" />
<element type="string" name="Lastname" minOccurs="1" maxOccurs="1" />
<element type="string" name="State" minOccurs="1" maxOccurs="1" />
<element type="string" name="Locale" minOccurs="0" maxOccurs="1" />
<element name="Roles" minOccurs="1" maxOccurs="1">
<complexType>
<sequence>
<element type="string" name="Role" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</complexType>
</element>
<element name="Properties" type="pr:Properties" minOccurs="0" maxOccurs="1" />
</sequence>
<attribute type="long" name="userId" use="required" />
<attribute type="string" name="username" use="required" />
<attribute type="string" name="password" use="required" />
</complexType>
<complexType name="Properties">
<sequence>
<element name="Property" minOccurs="0" maxOccurs="unbounded">
<complexType>
<simpleContent>
<extension base="string">
<attribute type="string" name="name" use="required" />
<attribute type="string" name="value" use="required" />
</extension>
</simpleContent>
</complexType>
</element>
</sequence>
</complexType>
<complexType name="Role" mixed="true">
<sequence>
<element name="Privilege" minOccurs="0" maxOccurs="unbounded">
<complexType>
<sequence>
<element type="string" name="AllAllowed" minOccurs="0" maxOccurs="1"/>
<element type="string" name="Allow" minOccurs="0" maxOccurs="unbounded" />
<element type="string" name="Deny" minOccurs="0" maxOccurs="unbounded" />
</sequence>
<attribute type="string" name="name" use="required" />
</complexType>
</element>
</sequence>
<attribute type="string" name="name" use="required" />
</complexType>
</schema>

View File

@ -0,0 +1,116 @@
package ch.eitchnet.privilege.test;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.nio.file.Files;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.eitchnet.privilege.base.PrivilegeException;
import ch.eitchnet.privilege.handler.PrivilegeHandler;
import ch.eitchnet.privilege.helper.PrivilegeInitializationHelper;
import ch.eitchnet.privilege.model.Certificate;
import ch.eitchnet.privilege.model.PrivilegeContext;
import ch.eitchnet.utils.helper.FileHelper;
public class AbstractPrivilegeTest {
protected static final Logger logger = LoggerFactory.getLogger(AbstractPrivilegeTest.class);
protected PrivilegeHandler privilegeHandler;
protected PrivilegeContext ctx;
protected void login(String username, byte[] password) {
Certificate certificate = privilegeHandler.authenticate(username, password);
assertTrue("Certificate is null!", certificate != null);
PrivilegeContext privilegeContext = privilegeHandler.getPrivilegeContext(certificate);
this.ctx = privilegeContext;
}
protected void logout() {
if (this.ctx != null) {
try {
PrivilegeContext privilegeContext = this.ctx;
this.ctx = null;
privilegeHandler.invalidateSession(privilegeContext.getCertificate());
} catch (PrivilegeException e) {
String msg = "There is no PrivilegeContext currently bound to the ThreadLocal!";
if (!e.getMessage().equals(msg))
throw e;
}
}
}
protected static void prepareConfigs(String dst, String configFilename, String usersFilename,
String rolesFilename) {
try {
String pwd = System.getProperty("user.dir");
File configPath = new File(pwd, "config");
File privilegeConfigFile = new File(configPath, configFilename);
File privilegeUsersFile = new File(configPath, usersFilename);
File privilegeRolesFile = new File(configPath, rolesFilename);
File targetPath = new File(pwd, "target/" + dst);
if (!targetPath.mkdirs())
throw new RuntimeException("Could not create parent " + targetPath);
File dstConfig = new File(targetPath, configFilename);
File dstUsers = new File(targetPath, usersFilename);
File dstRoles = new File(targetPath, rolesFilename);
// write config
String config = new String(Files.readAllBytes(privilegeConfigFile.toPath()), "UTF-8");
config = config.replace("${target}", dst);
Files.write(dstConfig.toPath(), config.getBytes("UTF-8"));
// copy model
Files.copy(privilegeUsersFile.toPath(), dstUsers.toPath());
Files.copy(privilegeRolesFile.toPath(), dstRoles.toPath());
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw new RuntimeException("Initialization failed", e);
}
}
protected static void removeConfigs(String dst) {
try {
String pwd = System.getProperty("user.dir");
File targetPath = new File(pwd, "target");
targetPath = new File(targetPath, dst);
if (targetPath.exists() && !FileHelper.deleteFile(targetPath, true)) {
throw new RuntimeException(
"Tmp configuration still exists and can not be deleted at " + targetPath.getAbsolutePath());
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw new RuntimeException("Initialization failed", e);
}
}
protected static File getPrivilegeConfigFile(String dst, String configFilename) {
try {
String pwd = System.getProperty("user.dir");
File targetPath = new File(pwd, "target");
targetPath = new File(targetPath, dst);
return new File(targetPath, configFilename);
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw new RuntimeException("Initialization failed", e);
}
}
protected void initialize(String dst, String configFilename) {
try {
File privilegeConfigFile = getPrivilegeConfigFile(dst, configFilename);
this.privilegeHandler = PrivilegeInitializationHelper.initializeFromXml(privilegeConfigFile);
} catch (Exception e) {
logger.error(e.getMessage(), e);
throw new RuntimeException("Initialization failed", e);
}
}
}

View File

@ -0,0 +1,48 @@
package ch.eitchnet.privilege.test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.File;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
public class PersistSessionsTest extends AbstractPrivilegeTest {
@BeforeClass
public static void init() throws Exception {
removeConfigs(PersistSessionsTest.class.getSimpleName());
prepareConfigs(PersistSessionsTest.class.getSimpleName(), "PrivilegeConfig.xml", "PrivilegeUsers.xml",
"PrivilegeRoles.xml");
}
@AfterClass
public static void destroy() throws Exception {
removeConfigs(PersistSessionsTest.class.getSimpleName());
}
@Before
public void setup() throws Exception {
initialize(PersistSessionsTest.class.getSimpleName(), "PrivilegeConfig.xml");
}
@Test
public void shouldPersistAndReloadSessions() {
// assert no sessions file
File sessionsFile = new File("target/PersistSessionsTest/sessions.dat");
assertFalse("Sessions File should no yet exist", sessionsFile.exists());
// login and assert sessions file was written
login("admin", "admin".getBytes());
this.privilegeHandler.isCertificateValid(ctx.getCertificate());
assertTrue("Sessions File should have been created!", sessionsFile.isFile());
// re-initialize and assert still logged in
initialize(PersistSessionsTest.class.getSimpleName(), "PrivilegeConfig.xml");
this.privilegeHandler.isCertificateValid(ctx.getCertificate());
}
}

View File

@ -0,0 +1,77 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import ch.eitchnet.privilege.model.IPrivilege;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class PrivilegeConflictMergeTest extends AbstractPrivilegeTest {
@BeforeClass
public static void init() throws Exception {
removeConfigs(PrivilegeConflictMergeTest.class.getSimpleName());
prepareConfigs(PrivilegeConflictMergeTest.class.getSimpleName(), "PrivilegeConfigMerge.xml",
"PrivilegeUsersMerge.xml", "PrivilegeRolesMerge.xml");
}
@AfterClass
public static void destroy() throws Exception {
removeConfigs(PrivilegeConflictMergeTest.class.getSimpleName());
}
@Before
public void setup() throws Exception {
initialize(PrivilegeConflictMergeTest.class.getSimpleName(), "PrivilegeConfigMerge.xml");
}
@Test
public void shouldMergePrivileges1() {
try {
login("userA", "admin".getBytes());
IPrivilege privilege = this.ctx.getPrivilege("Foo");
assertTrue(privilege.isAllAllowed());
assertTrue(privilege.getAllowList().isEmpty());
assertTrue(privilege.getDenyList().isEmpty());
} finally {
logout();
}
}
@Test
public void shouldMergePrivileges2() {
try {
login("userB", "admin".getBytes());
IPrivilege privilege = this.ctx.getPrivilege("Bar");
assertFalse(privilege.isAllAllowed());
assertEquals(2, privilege.getAllowList().size());
assertEquals(2, privilege.getDenyList().size());
} finally {
logout();
}
}
}

View File

@ -0,0 +1,755 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.fail;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.eitchnet.privilege.base.AccessDeniedException;
import ch.eitchnet.privilege.base.PrivilegeException;
import ch.eitchnet.privilege.handler.PrivilegeHandler;
import ch.eitchnet.privilege.i18n.PrivilegeMessages;
import ch.eitchnet.privilege.model.Certificate;
import ch.eitchnet.privilege.model.PrivilegeRep;
import ch.eitchnet.privilege.model.Restrictable;
import ch.eitchnet.privilege.model.RoleRep;
import ch.eitchnet.privilege.model.UserRep;
import ch.eitchnet.privilege.model.UserState;
import ch.eitchnet.privilege.test.model.TestRestrictable;
import ch.eitchnet.privilege.test.model.TestSystemUserAction;
import ch.eitchnet.privilege.test.model.TestSystemUserActionDeny;
import ch.eitchnet.utils.helper.ArraysHelper;
/**
* JUnit for performing Privilege tests. This JUnit is by no means complete, but checks the bare minimum.br />
*
* TODO add more tests, especially with deny and allow lists
*
* @author Robert von Burg <eitch@eitchnet.ch>
*/
@SuppressWarnings("nls")
public class PrivilegeTest extends AbstractPrivilegeTest {
private static final String ROLE_PRIVILEGE_ADMIN = "PrivilegeAdmin";
private static final String PRIVILEGE_USER_ACCESS = "UserAccessPrivilege";
private static final String ADMIN = "admin";
private static final byte[] PASS_ADMIN = "admin".getBytes();
private static final String BOB = "bob";
private static final String TED = "ted";
private static final String SYSTEM_USER_ADMIN = "system_admin";
private static final String SYSTEM_USER_ADMIN2 = "system_admin2";
private static final byte[] PASS_BOB = "admin1".getBytes();
private static final String ROLE_APP_USER = "AppUser";
private static final String ROLE_MY = "MyRole";
private static final String ROLE_MY2 = "MyRole2";
private static final String ROLE_CHANGE_PW = "changePw";
private static final String ROLE_TEMP = "temp";
private static final String ROLE_USER = "user";
private static final byte[] PASS_DEF = "def".getBytes();
private static final byte[] PASS_BAD = "123".getBytes();
private static final byte[] PASS_TED = "12345".getBytes();
private static final Logger logger = LoggerFactory.getLogger(PrivilegeTest.class);
@Rule
public ExpectedException exception = ExpectedException.none();
@BeforeClass
public static void init() throws Exception {
removeConfigs(PrivilegeTest.class.getSimpleName());
prepareConfigs(PrivilegeTest.class.getSimpleName(), "PrivilegeConfig.xml", "PrivilegeUsers.xml",
"PrivilegeRoles.xml");
}
@AfterClass
public static void destroy() throws Exception {
removeConfigs(PrivilegeTest.class.getSimpleName());
}
@Before
public void setup() throws Exception {
initialize(PrivilegeTest.class.getSimpleName(), "PrivilegeConfig.xml");
}
@Test
public void testAuthenticationOk() throws Exception {
try {
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
} finally {
logout();
}
}
public void testFailAuthenticationNOk() throws Exception {
this.exception.expect(AccessDeniedException.class);
this.exception.expectMessage("blabla");
try {
login(ADMIN, ArraysHelper.copyOf(PASS_BAD));
} finally {
logout();
}
}
public void testFailAuthenticationPWNull() throws Exception {
this.exception.expect(PrivilegeException.class);
this.exception.expectMessage("blabla");
try {
login(ADMIN, null);
} finally {
logout();
}
}
@Test
public void testAddRoleTemp() throws Exception {
try {
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
RoleRep roleRep = new RoleRep(ROLE_TEMP, new ArrayList<>());
Certificate certificate = this.ctx.getCertificate();
privilegeHandler.addRole(certificate, roleRep);
privilegeHandler.persist(certificate);
} finally {
logout();
}
}
@Test
public void testPerformRestrictableAsAdmin() throws Exception {
try {
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
// see if admin can perform restrictable
Restrictable restrictable = new TestRestrictable();
this.ctx.validateAction(restrictable);
} finally {
logout();
}
}
/**
* Tests if an action can be performed as a system user
*/
@Test
public void testPerformSystemRestrictable() throws Exception {
// create the action to be performed as a system user and then perform the action
TestSystemUserAction action = new TestSystemUserAction();
privilegeHandler.runAsSystem(SYSTEM_USER_ADMIN, action);
}
/**
* Checks that the system user can not perform a valid action, but illegal privilege
*/
@Test
public void testPerformSystemRestrictableFailPrivilege() throws Exception {
this.exception.expect(PrivilegeException.class);
this.exception.expectMessage(
"User system_admin does not have the privilege ch.eitchnet.privilege.handler.SystemUserAction");
try {
// create the action to be performed as a system user
TestSystemUserActionDeny action = new TestSystemUserActionDeny();
// and then perform the action
privilegeHandler.runAsSystem(SYSTEM_USER_ADMIN, action);
} finally {
logout();
}
}
/**
* Checks that the system user can not perform a valid action, but illegal privilege
*/
@Test
public void testPerformSystemRestrictableFailNoAdditionalPrivilege() throws Exception {
this.exception.expect(PrivilegeException.class);
this.exception.expectMessage(
"User system_admin2 does not have the privilege ch.eitchnet.privilege.handler.SystemUserAction needed for Restrictable ch.eitchnet.privilege.test.model.TestSystemUserActionDeny");
try {
// create the action to be performed as a system user
TestSystemUserActionDeny action = new TestSystemUserActionDeny();
// and then perform the action
privilegeHandler.runAsSystem(SYSTEM_USER_ADMIN2, action);
} finally {
logout();
}
}
/**
* System user may not login
*/
@Test
public void testLoginSystemUser() throws Exception {
this.exception.expect(AccessDeniedException.class);
this.exception.expectMessage("User system_admin is a system user and may not login!");
try {
login(SYSTEM_USER_ADMIN, SYSTEM_USER_ADMIN.getBytes());
} finally {
logout();
}
}
@Test
public void testPrivilegeContext() {
try {
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
Restrictable restrictable = new TestRestrictable();
this.ctx.validateAction(restrictable);
} finally {
logout();
}
}
@Test
public void shouldUpdateAdmin() {
try {
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
Certificate certificate = this.ctx.getCertificate();
// validate name is not yet set
UserRep user = privilegeHandler.getUser(certificate, ADMIN);
assertNotEquals("The", user.getFirstname());
assertNotEquals("Admin", user.getLastname());
// let's add a new user bob
UserRep userRep = new UserRep(null, ADMIN, "The", "Admin", null, null, null, null);
privilegeHandler.updateUser(certificate, userRep);
user = privilegeHandler.getUser(certificate, ADMIN);
assertEquals("The", user.getFirstname());
assertEquals("Admin", user.getLastname());
} finally {
logout();
}
}
@Test
public void shouldFailUpdateInexistantUser() {
exception.expect(PrivilegeException.class);
exception.expectMessage("User bob does not exist");
try {
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
Certificate certificate = this.ctx.getCertificate();
// let's add a new user bob
UserRep userRep = new UserRep(null, BOB, null, null, null, null, null, null);
privilegeHandler.updateUser(certificate, userRep);
} finally {
logout();
}
}
@Test
public void shouldFailUpdateAdminNoChanges() {
exception.expect(PrivilegeException.class);
exception.expectMessage("All updateable fields are empty for update of user admin");
try {
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
Certificate certificate = this.ctx.getCertificate();
// let's add a new user bob
UserRep userRep = new UserRep(null, ADMIN, null, null, null, null, null, null);
privilegeHandler.updateUser(certificate, userRep);
} finally {
logout();
}
}
@Test
public void shouldQueryUsers() {
try {
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
Certificate certificate = this.ctx.getCertificate();
UserRep selectorRep = new UserRep(null, ADMIN, null, null, null, null, null, null);
List<UserRep> users = privilegeHandler.queryUsers(certificate, selectorRep);
assertEquals(1, users.size());
assertEquals(ADMIN, users.get(0).getUsername());
} finally {
logout();
}
}
@Test
public void shouldQueryUsersByRoles() {
try {
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
Certificate certificate = this.ctx.getCertificate();
UserRep selectorRep = new UserRep(null, null, null, null, null,
new HashSet<>(Arrays.asList("PrivilegeAdmin")), null, null);
List<UserRep> users = privilegeHandler.queryUsers(certificate, selectorRep);
assertEquals(1, users.size());
assertEquals(ADMIN, users.get(0).getUsername());
} finally {
logout();
}
}
@Test
public void shouldQueryUsersByRoles2() {
try {
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
Certificate certificate = this.ctx.getCertificate();
UserRep selectorRep = new UserRep(null, null, null, null, null, new HashSet<>(Arrays.asList(ROLE_TEMP)),
null, null);
List<UserRep> users = privilegeHandler.queryUsers(certificate, selectorRep);
assertEquals(0, users.size());
} finally {
logout();
}
}
@Test
public void shouldDetectPrivilegeConflict1() {
exception.expect(PrivilegeException.class);
exception.expectMessage("User admin has conflicts for privilege ");
try {
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
Certificate certificate = this.ctx.getCertificate();
PrivilegeRep privilegeRep = new PrivilegeRep(PrivilegeHandler.PRIVILEGE_ACTION, "DefaultPrivilege", true,
Collections.emptySet(), Collections.emptySet());
privilegeHandler.addOrReplacePrivilegeOnRole(certificate, ROLE_APP_USER, privilegeRep);
} finally {
logout();
}
}
@Test
public void shouldDetectPrivilegeConflict2() {
exception.expect(PrivilegeException.class);
exception.expectMessage("User admin has conflicts for privilege ");
try {
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
Certificate certificate = this.ctx.getCertificate();
privilegeHandler.addRoleToUser(certificate, ADMIN, ROLE_MY);
privilegeHandler.addRoleToUser(certificate, ADMIN, ROLE_MY2);
} finally {
logout();
}
}
/**
* This test performs multiple tests which are dependent on each other as the following is done:
* <ul>
* <li>add user bob</li>
* <li>fail to auth as bob as user is not enabled</li>
* <li>enable bob</li>
* <li>fail to auth as bot as bob has no role</li>
* <li>add role user to bob</li>
* <li>auth as bob</li>
* <li>fail to add user ted as bob as bob is not admin</li>
* <li>add admin role to bob</li>
* <li>add user ted as bob</li>
* <li>fail to auth as ted as ted has no password</li>
* <li>set ted's password as bob</li>
* <li>ted changes own password</li>
* <li>auth as ted</li>
* <li>fail to perform restrictable as bob as no app role</li>
* <li>add app role to bob</li>
* <li>perform restrictable as bob</li>
* </ul>
*/
@Test
public void testUserStory() throws Exception {
addBobAsAdmin();
failAuthAsBobNotEnabled();
enableBob();
addRoleUser();
addRoleUserToBob();
authAsBob();
failAddTedAsBobNotAdmin();
addRoleAdminToBob();
addTedAsBob();
failAuthAsTedNoPass();
setPassForTedAsBob();
failSetSystemStateTed();
failTedChangesPwAndLocale();
addChangePwRoleToTed();
tedChangesOwnPassAndLocale();
failTedChangesOtherPwStateAndLocale();
authAsTed();
failPerformRestrictableAsBobNoRoleApp();
addRoleAppToBob();
performRestrictableAsBob();
}
private void failSetSystemStateTed() {
try {
// testEnableUserBob
login(BOB, ArraysHelper.copyOf(PASS_BOB));
Certificate certificate = this.ctx.getCertificate();
try {
privilegeHandler.setUserState(certificate, TED, UserState.SYSTEM);
fail("Should not be able to set user state to SYSTEM");
} catch (AccessDeniedException e) {
// ok
}
} finally {
logout();
}
}
private void failTedChangesOtherPwStateAndLocale() {
try {
// testTedChangesOwnPwd
login(TED, ArraysHelper.copyOf(PASS_TED));
Certificate certificate = this.ctx.getCertificate();
try {
privilegeHandler.setUserPassword(certificate, BOB, ArraysHelper.copyOf(PASS_TED));
fail("Should not be able to set password of other user, as missing privilege");
} catch (AccessDeniedException e) {
// ok
}
try {
privilegeHandler.setUserLocale(certificate, BOB, Locale.FRENCH);
fail("Should not be able to set locale of other user, as missing privilege");
} catch (AccessDeniedException e) {
// ok
}
try {
privilegeHandler.setUserState(certificate, BOB, UserState.DISABLED);
fail("Should not be able to set state of other user, as missing privilege");
} catch (AccessDeniedException e) {
// ok
}
} finally {
logout();
}
}
private void failTedChangesPwAndLocale() {
try {
// testTedChangesOwnPwd
login(TED, ArraysHelper.copyOf(PASS_DEF));
Certificate certificate = this.ctx.getCertificate();
try {
privilegeHandler.setUserPassword(certificate, TED, ArraysHelper.copyOf(PASS_TED));
fail("Should not be able to set password, as missing privilege");
} catch (AccessDeniedException e) {
// ok
}
try {
privilegeHandler.setUserLocale(certificate, TED, Locale.FRENCH);
fail("Should not be able to set locale, as missing privilege");
} catch (AccessDeniedException e) {
// ok
}
try {
privilegeHandler.setUserState(certificate, TED, UserState.ENABLED);
fail("Should not be able to set state, as missing privilege");
} catch (AccessDeniedException e) {
// ok
}
} finally {
logout();
}
}
private void addChangePwRoleToTed() {
try {
// add role user
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
PrivilegeRep passwordRep = new PrivilegeRep(PrivilegeHandler.PRIVILEGE_SET_USER_PASSWORD,
PRIVILEGE_USER_ACCESS, false, Collections.emptySet(), Collections.emptySet());
PrivilegeRep localeRep = new PrivilegeRep(PrivilegeHandler.PRIVILEGE_SET_USER_LOCALE, PRIVILEGE_USER_ACCESS,
false, Collections.emptySet(), Collections.emptySet());
RoleRep roleRep = new RoleRep(ROLE_CHANGE_PW, Arrays.asList(passwordRep, localeRep));
Certificate certificate = this.ctx.getCertificate();
privilegeHandler.addRole(certificate, roleRep);
privilegeHandler.addRoleToUser(certificate, TED, ROLE_CHANGE_PW);
logger.info("Added " + ROLE_CHANGE_PW + " to " + TED);
privilegeHandler.persist(certificate);
} finally {
logout();
}
}
private void performRestrictableAsBob() {
try {
// testPerformRestrictableAsBob
// Tests if the user bob, who now has AppUser role can perform restrictable
login(BOB, ArraysHelper.copyOf(PASS_BOB));
// see if bob can perform restrictable
Restrictable restrictable = new TestRestrictable();
this.ctx.validateAction(restrictable);
} finally {
logout();
}
}
private void addRoleAppToBob() {
try {
// testAddAppRoleToBob
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
Certificate certificate = this.ctx.getCertificate();
privilegeHandler.addRoleToUser(certificate, BOB, ROLE_APP_USER);
logger.info("Added " + ROLE_APP_USER + " to " + BOB);
privilegeHandler.persist(certificate);
} finally {
logout();
}
}
private void failPerformRestrictableAsBobNoRoleApp() {
try {
// testFailPerformRestrictableAsBob
// Tests if the user bob, who does not have AppUser role can perform restrictable
// this will fail as bob does not have role app
login(BOB, ArraysHelper.copyOf(PASS_BOB));
// see if bob can perform restrictable
Restrictable restrictable = new TestRestrictable();
this.ctx.validateAction(restrictable);
fail("Should fail as bob does not have role app");
} catch (AccessDeniedException e) {
String msg = "User bob does not have the privilege ch.eitchnet.privilege.test.model.TestRestrictable needed for Restrictable ch.eitchnet.privilege.test.model.TestRestrictable";
assertEquals(msg, e.getLocalizedMessage());
} finally {
logout();
}
}
private void authAsTed() {
try {
// testAuthAsTed
login(TED, ArraysHelper.copyOf(PASS_TED));
} finally {
logout();
}
}
private void tedChangesOwnPassAndLocale() {
try {
// testTedChangesOwnPwd
login(TED, ArraysHelper.copyOf(PASS_DEF));
Certificate certificate = this.ctx.getCertificate();
privilegeHandler.setUserPassword(certificate, TED, ArraysHelper.copyOf(PASS_TED));
privilegeHandler.setUserLocale(certificate, TED, Locale.FRENCH);
} finally {
logout();
}
}
private void setPassForTedAsBob() {
try {
// testSetTedPwdAsBob
login(BOB, ArraysHelper.copyOf(PASS_BOB));
// set ted's password to default
Certificate certificate = this.ctx.getCertificate();
privilegeHandler.setUserPassword(certificate, TED, ArraysHelper.copyOf(PASS_DEF));
privilegeHandler.persist(certificate);
} finally {
logout();
}
}
private void failAuthAsTedNoPass() {
try {
// testFailAuthAsTedNoPass
// Will fail because user ted has no password
login(TED, ArraysHelper.copyOf(PASS_TED));
fail("User Ted may not authenticate because the user has no password!");
} catch (PrivilegeException e) {
String msg = "User ted has no password and may not login!";
assertEquals(msg, e.getMessage());
} finally {
logout();
}
}
private void addTedAsBob() {
try {
UserRep userRep;
// testAddUserTedAsBob
login(BOB, ArraysHelper.copyOf(PASS_BOB));
// let's add a new user ted
HashSet<String> roles = new HashSet<>();
roles.add(ROLE_USER);
userRep = new UserRep(null, TED, "Ted", "Newman", UserState.ENABLED, roles, null,
new HashMap<String, String>());
Certificate certificate = this.ctx.getCertificate();
privilegeHandler.addUser(certificate, userRep, null);
logger.info("Added user " + TED);
privilegeHandler.persist(certificate);
} finally {
logout();
}
}
private void addRoleAdminToBob() {
try {
// testAddAdminRoleToBob
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
Certificate certificate = this.ctx.getCertificate();
privilegeHandler.addRoleToUser(certificate, BOB, ROLE_PRIVILEGE_ADMIN);
logger.info("Added " + ROLE_PRIVILEGE_ADMIN + " to " + ADMIN);
privilegeHandler.persist(certificate);
} finally {
logout();
}
}
private void failAddTedAsBobNotAdmin() {
Certificate certificate = null;
try {
UserRep userRep;
// testFailAddUserTedAsBob
// Will fail because user bob does not have admin rights
// auth as Bob
login(BOB, ArraysHelper.copyOf(PASS_BOB));
// let's add a new user Ted
userRep = new UserRep("1", TED, "Ted", "And then Some", UserState.NEW, new HashSet<String>(), null,
new HashMap<String, String>());
certificate = this.ctx.getCertificate();
privilegeHandler.addUser(certificate, userRep, null);
fail("User bob may not add a user as bob does not have admin rights!");
} catch (PrivilegeException e) {
String msg = MessageFormat.format(PrivilegeMessages.getString("Privilege.noprivilege.user"), //$NON-NLS-1$
BOB, PrivilegeHandler.PRIVILEGE_ADD_USER);
assertEquals(msg, e.getMessage());
} finally {
logout();
}
}
private void authAsBob() {
try {
// testAuthAsBob
login(BOB, ArraysHelper.copyOf(PASS_BOB));
} finally {
logout();
}
}
private void addRoleUserToBob() {
try {
// testAddRoleUserToBob
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
Certificate certificate = this.ctx.getCertificate();
privilegeHandler.addRoleToUser(certificate, BOB, ROLE_USER);
privilegeHandler.persist(certificate);
logout();
} finally {
logout();
}
}
private void addRoleUser() {
try {
// add role user
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
RoleRep roleRep = new RoleRep(ROLE_USER, new ArrayList<>());
Certificate certificate = this.ctx.getCertificate();
privilegeHandler.addRole(certificate, roleRep);
privilegeHandler.persist(certificate);
} finally {
logout();
}
}
private void enableBob() {
try {
// testEnableUserBob
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
Certificate certificate = this.ctx.getCertificate();
privilegeHandler.setUserState(certificate, BOB, UserState.ENABLED);
privilegeHandler.persist(certificate);
} finally {
logout();
}
}
private void failAuthAsBobNotEnabled() {
try {
// testFailAuthAsBob
// Will fail because user bob is not yet enabled
privilegeHandler.authenticate(BOB, ArraysHelper.copyOf(PASS_BOB));
fail("User Bob may not authenticate because the user is not yet enabled!");
} catch (PrivilegeException e) {
String msg = "User bob does not have state ENABLED and can not login!";
assertEquals(msg, e.getMessage());
} finally {
logout();
}
}
private void addBobAsAdmin() {
try {
login(ADMIN, ArraysHelper.copyOf(PASS_ADMIN));
// let's add a new user bob
UserRep userRep = new UserRep(null, BOB, "Bob", "Newman", UserState.NEW,
new HashSet<>(Arrays.asList(ROLE_MY)), null, new HashMap<String, String>());
Certificate certificate = this.ctx.getCertificate();
privilegeHandler.addUser(certificate, userRep, null);
logger.info("Added user " + BOB);
// set bob's password
privilegeHandler.setUserPassword(certificate, BOB, ArraysHelper.copyOf(PASS_BOB));
logger.info("Set Bob's password");
privilegeHandler.persist(certificate);
} finally {
logout();
}
}
}

View File

@ -0,0 +1,454 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.test;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.eitchnet.privilege.handler.DefaultEncryptionHandler;
import ch.eitchnet.privilege.handler.PrivilegeHandler;
import ch.eitchnet.privilege.handler.XmlPersistenceHandler;
import ch.eitchnet.privilege.model.IPrivilege;
import ch.eitchnet.privilege.model.UserState;
import ch.eitchnet.privilege.model.internal.PrivilegeContainerModel;
import ch.eitchnet.privilege.model.internal.PrivilegeImpl;
import ch.eitchnet.privilege.model.internal.Role;
import ch.eitchnet.privilege.model.internal.User;
import ch.eitchnet.privilege.xml.PrivilegeConfigDomWriter;
import ch.eitchnet.privilege.xml.PrivilegeConfigSaxReader;
import ch.eitchnet.privilege.xml.PrivilegeRolesDomWriter;
import ch.eitchnet.privilege.xml.PrivilegeRolesSaxReader;
import ch.eitchnet.privilege.xml.PrivilegeUsersDomWriter;
import ch.eitchnet.privilege.xml.PrivilegeUsersSaxReader;
import ch.eitchnet.utils.helper.FileHelper;
import ch.eitchnet.utils.helper.StringHelper;
import ch.eitchnet.utils.helper.XmlHelper;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
@SuppressWarnings("nls")
public class XmlTest {
private static final String TARGET_TEST = "./target/test";
private static final Logger logger = LoggerFactory.getLogger(XmlTest.class);
/**
* @throws Exception
* if something goes wrong
*/
@BeforeClass
public static void init() throws Exception {
cleanUp();
File tmpDir = new File("target/test");
if (tmpDir.exists())
FileHelper.deleteFile(tmpDir, false);
tmpDir.mkdirs();
}
@AfterClass
public static void cleanUp() throws Exception {
File tmpDir = new File("target/test");
if (!tmpDir.exists())
return;
File tmpFile = new File("target/test/PrivilegeTest.xml");
if (tmpFile.exists() && !tmpFile.delete()) {
throw new RuntimeException("Tmp still exists and can not be deleted at " + tmpFile.getAbsolutePath());
}
tmpFile = new File("target/test/PrivilegeUsersTest.xml");
if (tmpFile.exists() && !tmpFile.delete()) {
throw new RuntimeException("Tmp still exists and can not be deleted at " + tmpFile.getAbsolutePath());
}
tmpFile = new File("target/test/PrivilegeRolesTest.xml");
if (tmpFile.exists() && !tmpFile.delete()) {
throw new RuntimeException("Tmp still exists and can not be deleted at " + tmpFile.getAbsolutePath());
}
// and temporary parent
if (!tmpDir.delete()) {
throw new RuntimeException("Could not remove temporary parent for tmp " + tmpFile);
}
}
@Test
public void canReadConfig() {
PrivilegeContainerModel containerModel = new PrivilegeContainerModel();
PrivilegeConfigSaxReader saxReader = new PrivilegeConfigSaxReader(containerModel);
File xmlFile = new File("config/PrivilegeConfig.xml");
XmlHelper.parseDocument(xmlFile, saxReader);
logger.info(containerModel.toString());
// assert all objects read
assertNotNull(containerModel.getParameterMap());
assertNotNull(containerModel.getPolicies());
assertNotNull(containerModel.getEncryptionHandlerClassName());
assertNotNull(containerModel.getEncryptionHandlerParameterMap());
assertNotNull(containerModel.getPersistenceHandlerClassName());
assertNotNull(containerModel.getPersistenceHandlerParameterMap());
assertEquals(6, containerModel.getParameterMap().size());
assertEquals(3, containerModel.getPolicies().size());
assertEquals(1, containerModel.getEncryptionHandlerParameterMap().size());
assertEquals(3, containerModel.getPersistenceHandlerParameterMap().size());
// TODO extend assertions to actual model
}
@Test
public void canWriteConfig() {
Map<String, String> parameterMap = new HashMap<>();
Map<String, String> encryptionHandlerParameterMap = new HashMap<>();
Map<String, String> persistenceHandlerParameterMap = new HashMap<>();
parameterMap.put("autoPersistOnPasswordChange", "true");
encryptionHandlerParameterMap.put("hashAlgorithm", "SHA-256");
persistenceHandlerParameterMap.put("basePath", TARGET_TEST);
persistenceHandlerParameterMap.put("modelXmlFile", "PrivilegeModel.xml");
PrivilegeContainerModel containerModel = new PrivilegeContainerModel();
containerModel.setParameterMap(parameterMap);
containerModel.setEncryptionHandlerClassName(DefaultEncryptionHandler.class.getName());
containerModel.setEncryptionHandlerParameterMap(encryptionHandlerParameterMap);
containerModel.setPersistenceHandlerClassName(XmlPersistenceHandler.class.getName());
containerModel.setPersistenceHandlerParameterMap(persistenceHandlerParameterMap);
containerModel.addPolicy("DefaultPrivilege", "ch.eitchnet.privilege.policy.DefaultPrivilege");
File configFile = new File("./target/test/PrivilegeTest.xml");
PrivilegeConfigDomWriter configSaxWriter = new PrivilegeConfigDomWriter(containerModel, configFile);
configSaxWriter.write();
String fileHash = StringHelper.getHexString(FileHelper.hashFileSha256(configFile));
assertEquals("22d4ba39605d49c758184d9bd63beae5ccf8786f3dabbab45cd9f59c2afbcbd0", fileHash);
}
@Test
public void canReadUsers() {
PrivilegeUsersSaxReader xmlHandler = new PrivilegeUsersSaxReader();
File xmlFile = new File("config/PrivilegeUsers.xml");
XmlHelper.parseDocument(xmlFile, xmlHandler);
List<User> users = xmlHandler.getUsers();
assertNotNull(users);
assertEquals(3, users.size());
//
// users
//
// admin
User admin = findUser("admin", users);
assertEquals("1", admin.getUserId());
assertEquals("admin", admin.getUsername());
assertEquals("8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918", admin.getPassword());
assertEquals("Application", admin.getFirstname());
assertEquals("Administrator", admin.getLastname());
assertEquals(UserState.ENABLED, admin.getUserState());
assertEquals("en_gb", admin.getLocale().toString());
assertThat(admin.getRoles(), containsInAnyOrder("PrivilegeAdmin", "AppUser"));
Map<String, String> properties = admin.getProperties();
assertEquals(new HashSet<>(Arrays.asList("organization", "organizationalUnit")), properties.keySet());
assertEquals("eitchnet.ch", properties.get("organization"));
assertEquals("Development", properties.get("organizationalUnit"));
// system_admin
User systemAdmin = findUser("system_admin", users);
assertEquals("2", systemAdmin.getUserId());
assertEquals("system_admin", systemAdmin.getUsername());
assertEquals(null, systemAdmin.getPassword());
assertEquals("System User", systemAdmin.getFirstname());
assertEquals("Administrator", systemAdmin.getLastname());
assertEquals(UserState.SYSTEM, systemAdmin.getUserState());
assertEquals("en_gb", systemAdmin.getLocale().toString());
assertThat(systemAdmin.getRoles(), containsInAnyOrder("system_admin_privileges"));
assertTrue(systemAdmin.getProperties().isEmpty());
}
@Test
public void canReadRoles() {
PrivilegeRolesSaxReader xmlHandler = new PrivilegeRolesSaxReader();
File xmlFile = new File("config/PrivilegeRoles.xml");
XmlHelper.parseDocument(xmlFile, xmlHandler);
List<Role> roles = xmlHandler.getRoles();
assertNotNull(roles);
assertEquals(6, roles.size());
// assert model
//
// roles
//
// PrivilegeAdmin
Role privilegeAdmin = findRole("PrivilegeAdmin", roles);
assertEquals("PrivilegeAdmin", privilegeAdmin.getName());
assertEquals(14, privilegeAdmin.getPrivilegeNames().size());
IPrivilege privilegeAction = privilegeAdmin.getPrivilege(PrivilegeHandler.PRIVILEGE_ACTION);
assertFalse(privilegeAction.isAllAllowed());
assertEquals(3, privilegeAction.getAllowList().size());
assertEquals(0, privilegeAction.getDenyList().size());
assertEquals("DefaultPrivilege", privilegeAction.getPolicy());
IPrivilege privilegeAddRole = privilegeAdmin.getPrivilege(PrivilegeHandler.PRIVILEGE_ADD_ROLE);
assertTrue(privilegeAddRole.isAllAllowed());
assertEquals(0, privilegeAddRole.getAllowList().size());
assertEquals(0, privilegeAddRole.getDenyList().size());
IPrivilege privilegeRemRoleFromUser = privilegeAdmin
.getPrivilege(PrivilegeHandler.PRIVILEGE_REMOVE_ROLE_FROM_USER);
assertTrue(privilegeRemRoleFromUser.isAllAllowed());
assertEquals(0, privilegeRemRoleFromUser.getAllowList().size());
assertEquals(0, privilegeRemRoleFromUser.getDenyList().size());
// AppUser
Role appUser = findRole("AppUser", roles);
assertEquals("AppUser", appUser.getName());
assertEquals(new HashSet<>(Arrays.asList("ch.eitchnet.privilege.test.model.TestRestrictable")),
appUser.getPrivilegeNames());
IPrivilege testRestrictable = appUser.getPrivilege("ch.eitchnet.privilege.test.model.TestRestrictable");
assertEquals("ch.eitchnet.privilege.test.model.TestRestrictable", testRestrictable.getName());
assertEquals("DefaultPrivilege", testRestrictable.getPolicy());
assertTrue(testRestrictable.isAllAllowed());
assertEquals(0, testRestrictable.getAllowList().size());
assertEquals(0, testRestrictable.getDenyList().size());
// system_admin_privileges
Role systemAdminPrivileges = findRole("system_admin_privileges", roles);
assertEquals("system_admin_privileges", systemAdminPrivileges.getName());
assertEquals(2, systemAdminPrivileges.getPrivilegeNames().size());
assertThat(systemAdminPrivileges.getPrivilegeNames(),
containsInAnyOrder("ch.eitchnet.privilege.handler.SystemUserAction",
"ch.eitchnet.privilege.test.model.TestSystemRestrictable"));
IPrivilege testSystemUserAction = systemAdminPrivileges
.getPrivilege("ch.eitchnet.privilege.handler.SystemUserAction");
assertEquals("ch.eitchnet.privilege.handler.SystemUserAction", testSystemUserAction.getName());
assertEquals("DefaultPrivilege", testSystemUserAction.getPolicy());
assertFalse(testSystemUserAction.isAllAllowed());
assertEquals(1, testSystemUserAction.getAllowList().size());
assertEquals(1, testSystemUserAction.getDenyList().size());
IPrivilege testSystemRestrictable = systemAdminPrivileges
.getPrivilege("ch.eitchnet.privilege.test.model.TestSystemRestrictable");
assertEquals("ch.eitchnet.privilege.test.model.TestSystemRestrictable", testSystemRestrictable.getName());
assertEquals("DefaultPrivilege", testSystemRestrictable.getPolicy());
assertTrue(testSystemRestrictable.isAllAllowed());
assertEquals(0, testSystemRestrictable.getAllowList().size());
assertEquals(0, testSystemRestrictable.getDenyList().size());
// restrictedRole
Role restrictedRole = findRole("restrictedRole", roles);
assertEquals("restrictedRole", restrictedRole.getName());
assertEquals(1, restrictedRole.getPrivilegeNames().size());
assertThat(restrictedRole.getPrivilegeNames(),
containsInAnyOrder("ch.eitchnet.privilege.handler.SystemUserAction"));
IPrivilege testSystemUserAction2 = restrictedRole
.getPrivilege("ch.eitchnet.privilege.handler.SystemUserAction");
assertEquals("ch.eitchnet.privilege.handler.SystemUserAction", testSystemUserAction2.getName());
assertEquals("DefaultPrivilege", testSystemUserAction2.getPolicy());
assertFalse(testSystemUserAction2.isAllAllowed());
assertEquals(1, testSystemUserAction2.getAllowList().size());
assertEquals(1, testSystemUserAction2.getDenyList().size());
assertThat(testSystemUserAction2.getAllowList(), containsInAnyOrder("hello"));
assertThat(testSystemUserAction2.getDenyList(), containsInAnyOrder("goodbye"));
}
/**
* @param username
* @param users
* @return
*/
private User findUser(String username, List<User> users) {
for (User user : users) {
if (user.getUsername().equals(username))
return user;
}
throw new RuntimeException("No user exists with username " + username);
}
/**
* @param name
* @param roles
* @return
*/
private Role findRole(String name, List<Role> roles) {
for (Role role : roles) {
if (role.getName().equals(name))
return role;
}
throw new RuntimeException("No role exists with name " + name);
}
@Test
public void canWriteUsers() {
Map<String, String> propertyMap;
Set<String> userRoles;
List<User> users = new ArrayList<>();
propertyMap = new HashMap<>();
propertyMap.put("prop1", "value1");
userRoles = new HashSet<>();
userRoles.add("role1");
User user1 = new User("1", "user1", "blabla", "Bob", "White", UserState.DISABLED, userRoles, Locale.ENGLISH,
propertyMap);
users.add(user1);
propertyMap = new HashMap<>();
propertyMap.put("prop2", "value2");
userRoles = new HashSet<>();
userRoles.add("role2");
User user2 = new User("2", "user2", "haha", "Leonard", "Sheldon", UserState.ENABLED, userRoles, Locale.ENGLISH,
propertyMap);
users.add(user2);
File modelFile = new File("./target/test/PrivilegeUsersTest.xml");
PrivilegeUsersDomWriter configSaxWriter = new PrivilegeUsersDomWriter(users, modelFile);
configSaxWriter.write();
PrivilegeUsersSaxReader xmlHandler = new PrivilegeUsersSaxReader();
XmlHelper.parseDocument(modelFile, xmlHandler);
List<User> parsedUsers = xmlHandler.getUsers();
assertNotNull(parsedUsers);
assertEquals(2, parsedUsers.size());
User parsedUser1 = parsedUsers.stream().filter(u -> u.getUsername().equals("user1")).findAny().get();
User parsedUser2 = parsedUsers.stream().filter(u -> u.getUsername().equals("user2")).findAny().get();
assertEquals(user1.getFirstname(), parsedUser1.getFirstname());
assertEquals(user1.getLastname(), parsedUser1.getLastname());
assertEquals(user1.getLocale(), parsedUser1.getLocale());
assertEquals(user1.getPassword(), parsedUser1.getPassword());
assertEquals(user1.getProperties(), parsedUser1.getProperties());
assertEquals(user1.getUserId(), parsedUser1.getUserId());
assertEquals(user1.getUserState(), parsedUser1.getUserState());
assertEquals(user1.getRoles(), parsedUser1.getRoles());
assertEquals(user2.getFirstname(), parsedUser2.getFirstname());
assertEquals(user2.getLastname(), parsedUser2.getLastname());
assertEquals(user2.getLocale(), parsedUser2.getLocale());
assertEquals(user2.getPassword(), parsedUser2.getPassword());
assertEquals(user2.getProperties(), parsedUser2.getProperties());
assertEquals(user2.getUserId(), parsedUser2.getUserId());
assertEquals(user2.getUserState(), parsedUser2.getUserState());
assertEquals(user2.getRoles(), parsedUser2.getRoles());
}
@Test
public void canWriteRoles() {
Map<String, IPrivilege> privilegeMap;
List<Role> roles = new ArrayList<>();
Set<String> list = Collections.emptySet();
privilegeMap = new HashMap<>();
privilegeMap.put("priv1", new PrivilegeImpl("priv1", "DefaultPrivilege", true, list, list));
Role role1 = new Role("role1", privilegeMap);
roles.add(role1);
privilegeMap = new HashMap<>();
Set<String> denyList = new HashSet<>();
denyList.add("myself");
Set<String> allowList = new HashSet<>();
allowList.add("other");
privilegeMap.put("priv2", new PrivilegeImpl("priv2", "DefaultPrivilege", false, denyList, allowList));
Role role2 = new Role("role2", privilegeMap);
roles.add(role2);
File modelFile = new File("./target/test/PrivilegeRolesTest.xml");
PrivilegeRolesDomWriter configSaxWriter = new PrivilegeRolesDomWriter(roles, modelFile);
configSaxWriter.write();
PrivilegeRolesSaxReader xmlHandler = new PrivilegeRolesSaxReader();
XmlHelper.parseDocument(modelFile, xmlHandler);
List<Role> parsedRoles = xmlHandler.getRoles();
assertNotNull(parsedRoles);
assertEquals(2, parsedRoles.size());
assertEquals(2, parsedRoles.size());
Role parsedRole1 = parsedRoles.stream().filter(r -> r.getName().equals("role1")).findAny().get();
Role parsedRole2 = parsedRoles.stream().filter(r -> r.getName().equals("role2")).findAny().get();
Set<String> privilegeNames = role1.getPrivilegeNames();
assertEquals(privilegeNames, parsedRole1.getPrivilegeNames());
for (String privilegeName : privilegeNames) {
IPrivilege privilege = role1.getPrivilege(privilegeName);
IPrivilege privilege2 = parsedRole1.getPrivilege(privilegeName);
assertNotNull(privilege);
assertNotNull(privilege2);
assertEquals(privilege.isAllAllowed(), privilege2.isAllAllowed());
assertEquals(privilege.getAllowList(), privilege2.getAllowList());
assertEquals(privilege.getDenyList(), privilege2.getDenyList());
assertEquals(privilege.getName(), privilege2.getName());
assertEquals(privilege.getPolicy(), privilege2.getPolicy());
}
assertEquals(role2.getPrivilegeNames(), parsedRole2.getPrivilegeNames());
privilegeNames = role2.getPrivilegeNames();
for (String privilegeName : privilegeNames) {
IPrivilege privilege = role2.getPrivilege(privilegeName);
IPrivilege privilege2 = parsedRole2.getPrivilege(privilegeName);
assertNotNull(privilege);
assertNotNull(privilege2);
assertEquals(privilege.isAllAllowed(), privilege2.isAllAllowed());
assertEquals(privilege.getAllowList(), privilege2.getAllowList());
assertEquals(privilege.getDenyList(), privilege2.getDenyList());
assertEquals(privilege.getName(), privilege2.getName());
assertEquals(privilege.getPolicy(), privilege2.getPolicy());
}
}
}

View File

@ -0,0 +1,42 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.test.model;
import ch.eitchnet.privilege.model.Restrictable;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*
*/
public class TestRestrictable implements Restrictable {
/**
* @see ch.eitchnet.privilege.model.Restrictable#getPrivilegeName()
*/
@Override
public String getPrivilegeName() {
return TestRestrictable.class.getName();
}
/**
* @see ch.eitchnet.privilege.model.Restrictable#getPrivilegeValue()
*/
@Override
public Object getPrivilegeValue() {
return TestRestrictable.class.getName();
}
}

View File

@ -0,0 +1,42 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.test.model;
import ch.eitchnet.privilege.model.Restrictable;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*
*/
public class TestSystemRestrictable implements Restrictable {
/**
* @see ch.eitchnet.privilege.model.Restrictable#getPrivilegeName()
*/
@Override
public String getPrivilegeName() {
return TestSystemRestrictable.class.getName();
}
/**
* @see ch.eitchnet.privilege.model.Restrictable#getPrivilegeValue()
*/
@Override
public Object getPrivilegeValue() {
return TestSystemRestrictable.class.getName();
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.test.model;
import ch.eitchnet.privilege.handler.SystemUserAction;
import ch.eitchnet.privilege.model.PrivilegeContext;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*
*/
public class TestSystemUserAction extends SystemUserAction {
@Override
public void execute(PrivilegeContext context) {
TestSystemRestrictable restrictable = new TestSystemRestrictable();
context.validateAction(restrictable);
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* 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.
*/
package ch.eitchnet.privilege.test.model;
import ch.eitchnet.privilege.handler.SystemUserAction;
import ch.eitchnet.privilege.model.PrivilegeContext;
/**
* @author Robert von Burg <eitch@eitchnet.ch>
*
*/
public class TestSystemUserActionDeny extends SystemUserAction {
@Override
public void execute(PrivilegeContext privilegeContext) {
TestRestrictable restrictable = new TestRestrictable();
privilegeContext.validateAction(restrictable);
}
}

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration PUBLIC
"-//APACHE//DTD LOG4J 1.2//EN" "http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/doc-files/log4j.dtd">
<log4j:configuration debug="false" xmlns:log4j='http://jakarta.apache.org/log4j/'>
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %5p [%t] %C{1} %M - %m%n" />
</layout>
</appender>
<appender name="FILE" class="org.apache.log4j.FileAppender">
<param name="File" value="sample.log"/>
<param name="BufferedIO" value="true" />
<param name="Append" value="true" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %5p [%t] %C{1} %M - %m%n" />
</layout>
</appender>
<logger name="ch.eitchnet">
<level value="info" />
</logger>
<root>
<priority value="info" />
<appender-ref ref="CONSOLE" />
<!-- appender-ref ref="FILE" / -->
</root>
</log4j:configuration>