Commit bdbd525f authored by Gradl, Tobias's avatar Gradl, Tobias
Browse files

12: Compose some initial documentation

Task-Url: #12
parent 7e15d331
Pipeline #17851 passed with stage
in 1 minute and 49 seconds
......@@ -52,7 +52,7 @@ Include the dependency to dariahsp-core in your `pom.xml`.
<dependency>
<groupId>eu.dariah.de</groupId>
<artifactId>dariahsp-core</artifactId>
<version>2.0.0-SNAPSHOT</version>
<version>2.0.0-RELEASE</version>
</dependency>
```
......@@ -90,12 +90,14 @@ repositories {
Include the dependency to dariahsp-core in your `build.gradle`.
```
implementation 'eu.dariah.de:dariahsp-core:2.0.0-SNAPSHOT'
implementation 'eu.dariah.de:dariahsp-core:2.0.0-RELEASE'
```
### 2.3 Manual download
The library and sample application can be downloaded from the Maven repository. In addition, build artifacts are composed and held at the GitLab repository of the project. For latest published builds see [dariahsp-core](https://gitlab.rz.uni-bamberg.de/dariah/dariahsp/-/jobs/artifacts/v2.0/browse/dariahsp-core/build/libs/?job=build) and [dariahsp-sample-boot](https://gitlab.rz.uni-bamberg.de/dariah/dariahsp/-/jobs/artifacts/v2.0/browse/dariahsp-sample-boot/build/libs/?job=build). Please not that while a new version is being prepared, a 404 error is issued when following these links.
The library and sample application can be downloaded from the [Maven repository](https://minfba.de.dariah.eu/nexus/#browse/browse:minfba-central:eu%2Fdariah%2Fde%2Fdariahsp-core). In addition, build artifacts are also composed and held at the GitLab repository of the project. For the latest published builds see [dariahsp-core](https://gitlab.rz.uni-bamberg.de/dariah/dariahsp/-/jobs/artifacts/v2.0/browse/dariahsp-core/build/libs/?job=build) and [dariahsp-sample-boot](https://gitlab.rz.uni-bamberg.de/dariah/dariahsp/-/jobs/artifacts/v2.0/browse/dariahsp-sample-boot/build/libs/?job=build) respectively.
Please note that while new artifacts are being prepared, a 404 error is issued when following these links. In occurring cases, we advise to wait for the completion of the build and download the fresh artifacts thereafter.
## 3. Security concepts and entry points
......@@ -115,49 +117,75 @@ One component requires _adaption_ in implementing applications:
## 4. Configuration
### Minimal working configuration
A minimal working configuration enables the local authentication method and provides local user accounts.
Configuration properties are specified here and in the sample boot app by means of anh according YAML configuration file.
## Local user accounts
The library supports a local authentication method that is purely based on application configuration properties. A working example including all configurable aspects:
## 4.1 Minimal working configuration
A minimal working configuration enables the **local authentication** method and defines **local user accounts**. The following configuration snippet includes an *admin* user with a specified BCrypt-encrypted password.
```yaml
#Minimal working sample configuration with local authentication enabled and one configured user
auth:
local:
enabled: true
#Password hash for: 1234
users:
- username: 'admin'
passhash: '$2y$10$nmTcpRxs.RFUstkJJms6U.AW61Jmr64s9VNQLuhpU8gYrgzCapwka'
```
A more sophisticated configuration of the local authentication method could involve roles and role mappings along with a configured hierarchy between the roles
In order to facilitate BCrypt encryption of passwords without having to rely on online generators, the `dariah-core` library implements a CLI-based generator. Due to required dependencies, usage of the so called fatjar is required, which can be downloaded from the [build artifacts](https://gitlab.rz.uni-bamberg.de/dariah/dariahsp/-/jobs/artifacts/v2.0/browse/dariahsp-core/build/libs/?job=build) or the [Maven repository](https://minfba.de.dariah.eu/nexus/#browse/browse:minfba-central:eu%2Fdariah%2Fde%2Fdariahsp-core).
```
$ java -jar dariahsp-core-2.0.0-RELEASE-fatjar.jar
CLI Tool to create BCrypt passwords to be used with a dariahsp derived application
------------------------------------------------------
Please choose rounds [4-31; default: 10]
Provide the password that you want encoded (minimum 6 characters, no leading/trailing whitespace):
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
BCrypt computation successful:
$2y$10$nmTcpRxs.RFUstkJJms6U.AW61Jmr64s9VNQLuhpU8gYrgzCapwka
```
## 4.2 Roles and mappings
Role management and configuration in the dariahsp-core library follow three basic concepts:
* User accounts *can provide information on roles*.
* in case of the *SAML authentication* method, these roles are managed externally within the Identify Providers
* for *local authentication*, roles are attached as attributes to user specifications
* Due to limited control of user roles in external scenarios (SAML), user roles are mapped to permission definitions that are fully under control of an implementing application; configured `permissionDefintions`:
* specify an internal name of the `permissionSet` against which security can be applied
* define a numeric permission `level` against which authorization can be validated (e.g. level must be gte 50)
* identify actual mappings to the (potentially) external roles; mapping configuration is specified per authentication method (currently `local` or `saml`)
* A hierarchy of permission definitions can be specified in order to authorize against minimal permission sets. In the sample configuration below, a security expression checking for a permission `ROLE_CONTRIBUTOR` is satisfied by both the `admin` and `contributor` users due to the configured permission hierarchy.
```yaml
auth:
#settings under roleHierarchy and roleDefinitions apply to all supported authentication methods
rolehierarchy: ROLE_ADMINISTRATOR > ROLE_CONTRIBUTOR > ROLE_USER
roleDefinitions:
- role: ADMINISTRATOR
#settings under permissionHierarchy and permissionDefinitions apply to all supported authentication methods
permissionHierarchy: ROLE_ADMINISTRATOR > ROLE_CONTRIBUTOR > ROLE_USER
permissionDefinitions:
- permissionSet: ADMINISTRATOR
level: 100
mappings:
local: ["application_admin"]
- role: CONTRIBUTOR
roleMappings:
local: ["application_admin"]
saml: ["application_admin"]
- permissionSet: CONTRIBUTOR
level: 50
mappings:
roleMappings:
local: ["application_contributor"]
- role: USER
saml: ["application_contributor"]
- permissionSet: USER
level: 10
mappings:
roleMappings:
local: ["application_user"]
saml: ["application_user"]
#Enabled local authentication method with three configured users
local:
enabled: true
authorizerName: local
#Same password for each user: 1234
users:
......@@ -172,27 +200,106 @@ auth:
roles: ["application_user"]
```
## 4.3 SAML-based authentication
The configuration sample below shows important attributes that should be adapted for enabling SAML-based authentication.
### Java Keystore
Even with the *local* authentication method, the dariahsp-sample application requires the configuration of a Java keystore (jks). This is mainly due to the SAML metadata generation functionality, which is available when local logins are used in order to help with installations of SAML service providers: starting the sample application in local authentication mode, the home screen of the application shows two links *SAML metadata...*, which support SAML metadata management (see SAML section below).
```yaml
auth:
# This base URL must indicate the externally visible FQDN
baseUrl: http://localhost:8080
permissionHierarchy: ROLE_ADMINISTRATOR > ROLE_CONTRIBUTOR > ROLE_USER
permissionDefinitions:
- permissionSet: ADMINISTRATOR
level: 100
roleMappings:
local: ["application_admin"]
saml: ["application_admin"]
- permissionSet: CONTRIBUTOR
level: 50
roleMappings:
local: ["application_contributor"]
saml: ["application_contributor"]
- permissionSet: USER
level: 10
roleMappings:
local: ["application_user"]
saml: ["application_user"]
saml:
keystore:
path: /path/to/keystore.jks
pass: keystore_password
alias: keypair_alias
aliaspass: private_key_password
metadata:
# URL is identical in all current DARIAH installations
url: https://aaiproxy.de.dariah.eu/idp/
sp:
# Configuration below is identical in all current DARIAH installations
attributesIncompleteRedirectUrl: "https://auth.de.dariah.eu/cgi-bin/selfservice/ldapportal.pl"
attributeGroups:
- check: AND
attributes:
- friendlyName: mail
name: urn:oid:0.9.2342.19200300.100.1.3
nameFormat: urn:oasis:names:tc:SAML:2.0:attrname-format:uri
- friendlyName: dariahTermsOfUse
name: urn:oid:1.3.6.1.4.1.10126.1.52.4.15
nameFormat: urn:oasis:names:tc:SAML:2.0:attrname-format:uri
- friendlyName: eduPersonPrincipalName
mappedAttribute: id
name: urn:oid:1.3.6.1.4.1.5923.1.1.1.6
nameFormat: urn:oasis:names:tc:SAML:2.0:attrname-format:uri
- check: OPTIONAL
attributes:
- friendlyName: mail
name: urn:oid:0.9.2342.19200300.100.1.3
nameFormat: urn:oasis:names:tc:SAML:2.0:attrname-format:uri
- friendlyName: displayName
mappedAttribute: username
name: urn:oid:2.16.840.1.113730.3.1.241
nameFormat: urn:oasis:names:tc:SAML:2.0:attrname-format:uri
- friendlyName: isMemberOf
mappedAttribute: externalRoles
name: urn:oid:1.3.6.1.4.1.5923.1.5.1.1
nameFormat: urn:oasis:names:tc:SAML:2.0:attrname-format:uri
```
### 4.3.1 IdP metadata
Provide the URL of the desired **IdP or metadata federation**. In case of DARIAH/CLARIAH implementations, all current services use the URL as detailed in the sample above.
### 4.3.2 Java KeyStore (JKS)
This library requires an existing Java KeyStore (JKS) that contains a private/public keypair that can be used for signature and encryption purposes. Depending on the addressed IdP or proxy, different requirements to used keys could apply. Once setup, set the appropriate configuration parameters of `saml.keystore.{path,pass,alias,aliaspass}`
#### Simple KeyStore generation
If you are setting up a DARIAH/CLARIAH service, a keystore - along with the required keypair can be created as such:
```
keytool -genkeypair -alias keypair_alias -keypass private_key_password -keystore sample_keystore.jks -storepass keystore_password -keyalg RSA -keysize 4096 -validity 3650
```
### Creating a KeyStore from an existing keypair
Based on a X.509 keypair and certificate chains, a keystore can easily be consolidated with `openssl` and the `keytool` (comes with Java installation). The followings steps show the commands for the example of the keystore for minfba.de.dariah.eu and the appropriate input. Please modify accordingly:
#### 1. Convert pem/pem keypair to p12 for easier input
1. Convert pem/pem keypair to p12 for easier input
For the -name argument make sure to chose as *name* the later alias of the keypair in the keystore.
```
$ openssl pkcs12 -export -name minfba.de.dariah.eu -in minfba-de-dariah-eu.crt -inkey minfba-de-dariah-eu.key > minfba-de-dariah-eu.p12
```
#### 2. Import p12 keypair and create Java keystore
2. Import p12 keypair and create Java keystore
Specified in the following step with the -alias argument note the reuse of the same key name as above. Basically this step imports an existing PKCS based "keystore" into a newly created jks.
```
$ keytool -importkeystore -alias minfba.de.dariah.eu -srckeystore minfba-de-dariah-eu.p12 -destkeystore minfba-de-dariah-eu.jks -srcstoretype pkcs12
```
#### 3. Import required trusted ca certificates
3. Import required trusted ca certificates
In the particular DARIAH-DE case this means 1) the chain of our keypair and 2) the trusted SAML metadata provider keychains of the [DFN AAI](https://www.aai.dfn.de/teilnahme/metadaten/).
```
......@@ -201,25 +308,5 @@ $ keytool -import -trustcacerts -alias dfn-aai -file dfn-aai.pem -keystore minfb
$ keytool -import -trustcacerts -alias dfn-aai-g2 -file dfn-aai.g2.pem -keystore minfba-de-dariah-eu.jks
```
#### GUI Support for Java Keystores
A convenient GUI-based option to view and edit Java keystore can be found in the [KeyStore Explorer](http://keystore-explorer.org/)
### Local user accounts
Local user accounts are configured in the central configuration file of the sample application. Passwords are encoded as Bcrypt hashes. In order to create your own hashes a convenience method has been implemented within the dariahsp-core library. As there are some required dependencies, you can download the latest [dariahsp-core-*-jar-with-dependencies.jar](https://minfba.de.dariah.eu/artifactory/list/dariah-minfba-snapshots/eu/dariah/de/dariahsp-core/).
To then create bcrypt passwords from a shell:
```
$ java -cp dariahsp-core-0.0.4-SNAPSHOT-jar-with-dependencies.jar eu.dariah.de.dariahsp.local.BCryptPasswordCreator
```
## dariahsp-core library
## dariahsp-sample-boot app
The Spring Boot based application is documented in its module: [dariahsp-sample-boot]
### 4.3.3 Attribute groups
......@@ -6,8 +6,8 @@ import java.util.Set;
import lombok.Data;
@Data
public class RoleDefinition {
private String role;
public class PermissionDefinition {
private String permissionSet;
private int level;
private Map<String,Set<String>> mappings;
private Map<String,Set<String>> roleMappings;
}
......@@ -48,8 +48,8 @@ public class SecurityConfig {
private final SAMLSecurity saml = new SAMLSecurity();
private String salt;
private String roleHierarchy;
private List<RoleDefinition> roleDefinitions;
private String permissionHierarchy;
private List<PermissionDefinition> permissionDefinitions;
private String baseUrl = "http://localhost:8080";
private String defaultLoginUrl = null;
private String defaultLogoutUrl = null;
......@@ -87,8 +87,8 @@ public class SecurityConfig {
@Bean
public RoleHierarchy roleHierarchy() {
RoleHierarchyImpl r = new RoleHierarchyImpl();
r.setHierarchy(roleHierarchy);
log.info("RoleHierarchy configured: {}", roleHierarchy);
r.setHierarchy(permissionHierarchy);
log.info("PermissionHierarchy configured: {}", permissionHierarchy);
return r;
}
......@@ -146,7 +146,13 @@ public class SecurityConfig {
cfg.setMaximumAuthenticationLifetime(saml.getSp().getMaxAuthAge());
cfg.setSignatureAlgorithms(saml.getSp().getSigningMethods());
cfg.setSignatureReferenceDigestMethods(saml.getSp().getDigestMethods());
cfg.setServiceProviderEntityId(saml.getSp().getEntityId());
if (saml.getSp().getEntityId()!=null) {
cfg.setServiceProviderEntityId(saml.getSp().getEntityId());
} else {
cfg.setServiceProviderEntityId(baseUrl);
}
cfg.setSpLogoutRequestSigned(saml.getSp().isLogoutRequestSigned());
cfg.setWantsAssertionsSigned(saml.getSp().isWantsAssertionsSigned());
cfg.setWantsResponsesSigned(saml.getSp().isWantsResponsesSigned());
......@@ -176,13 +182,13 @@ public class SecurityConfig {
private SamlProfileCreator saml2ProfileCreator() {
SamlProfileCreator saml2ProfileCreator = new SamlProfileCreator(this, saml.getAuthorizerName());
saml2ProfileCreator.setRoleDefinitions(roleDefinitions);
saml2ProfileCreator.setPermissionDefinitions(permissionDefinitions);
return saml2ProfileCreator;
}
private LocalProfileCreator localProfileCreator() {
LocalProfileCreator localProfileCreator = new LocalProfileCreator(local.getAuthorizerName());
localProfileCreator.setRoleDefinitions(roleDefinitions);
localProfileCreator.setPermissionDefinitions(permissionDefinitions);
return localProfileCreator;
}
}
......@@ -23,7 +23,7 @@ public class ServiceProvider {
private int maxAuthAge = 3600;
private String entityId;
private int httpClientTimoutMs = 2000;
private boolean signMetadata;
private boolean signMetadata = true;
private List<String> signingMethods;
private List<String> digestMethods;
private List<String> supportedProtocols;
......
......@@ -5,7 +5,7 @@ import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import eu.dariah.de.dariahsp.config.RoleDefinition;
import eu.dariah.de.dariahsp.config.PermissionDefinition;
import eu.dariah.de.dariahsp.model.ExtendedUserProfile;
import lombok.Data;
......@@ -13,18 +13,18 @@ import lombok.Data;
public abstract class BaseProfileCreator {
public static final String ROLE_PREFIX = "ROLE_";
protected final String clientName;
protected List<RoleDefinition> roleDefinitions;
protected List<PermissionDefinition> permissionDefinitions;
protected Set<RoleDefinition> getMappedRoles(ExtendedUserProfile profile) {
Set<RoleDefinition> roles = new LinkedHashSet<>();
for (RoleDefinition rm : roleDefinitions) {
for (String client : rm.getMappings().keySet()) {
protected Set<PermissionDefinition> getMappedRoles(ExtendedUserProfile profile) {
Set<PermissionDefinition> roles = new LinkedHashSet<>();
for (PermissionDefinition rm : permissionDefinitions) {
for (String client : rm.getRoleMappings().keySet()) {
if (!client.equals(clientName)) {
continue;
}
for (String extRole : profile.getExternalRoles()) {
if (!extRole.trim().isEmpty() &&
rm.getMappings().get(client).contains(extRole.trim()) &&
rm.getRoleMappings().get(client).contains(extRole.trim()) &&
!roles.contains(rm)) {
roles.add(rm);
}
......@@ -37,14 +37,14 @@ public abstract class BaseProfileCreator {
protected void mapAndAssignRoles(ExtendedUserProfile profile) {
if (this.canMapRoles(profile)) {
// Determine applicable role definitions
Set<RoleDefinition> mappedDefinitions = this.getMappedRoles(profile);
Set<PermissionDefinition> mappedDefinitions = this.getMappedRoles(profile);
// Set applicable roles as Strings
profile.setRoles(mappedDefinitions.stream()
.map(mr -> ROLE_PREFIX + mr.getRole().toUpperCase())
.map(pd -> pd.getPermissionSet().toUpperCase())
.collect(Collectors.toSet()));
// Set maximum applicable level
profile.setLevel(mappedDefinitions.stream()
.mapToInt(RoleDefinition::getLevel)
.mapToInt(PermissionDefinition::getLevel)
.max().orElse(0));
}
}
......@@ -52,6 +52,6 @@ public abstract class BaseProfileCreator {
private boolean canMapRoles(ExtendedUserProfile profile) {
return clientName!=null &&
profile.getExternalRoles()!=null && !profile.getExternalRoles().isEmpty() &&
roleDefinitions!=null && !roleDefinitions.isEmpty();
permissionDefinitions!=null && !permissionDefinitions.isEmpty();
}
}
}
\ No newline at end of file
......@@ -5,21 +5,21 @@ auth:
#defaultLoginUrl: ${auth.baseUrl}
#defaultLogoutUrl: ${auth.baseUrl}
salt: Qmwp4CO7LDkOUDouAcCcUqd9ZGNbRG5Jyr5lpntOuB9
rolehierarchy: ROLE_ADMINISTRATOR > ROLE_CONTRIBUTOR > ROLE_USER
roleDefinitions:
- role: ADMINISTRATOR
permissionHierarchy: ROLE_ADMINISTRATOR > ROLE_CONTRIBUTOR > ROLE_USER
permissionDefinitions:
- permissionSet: ADMINISTRATOR
level: 100
mappings:
roleMappings:
local: ["application_admin"]
saml: ["application_admin"]
- role: CONTRIBUTOR
- permissionSet: CONTRIBUTOR
level: 50
mappings:
roleMappings:
local: ["application_contributor"]
saml: ["application_contributor"]
- role: USER
- permissionSet: USER
level: 10
mappings:
roleMappings:
local: ["application_user"]
saml: ["application_user"]
local:
......
......@@ -17,21 +17,21 @@ auth:
defaultLoginUrl: ${auth.baseUrl}
defaultLogoutUrl: ${auth.baseUrl}
salt: Qmwp4CO7LDkOUDouAcCcUqd9ZGNbRG5Jyr5lpntOuB9
rolehierarchy: ROLE_ADMINISTRATOR > ROLE_CONTRIBUTOR > ROLE_USER
roleDefinitions:
- role: ADMINISTRATOR
permissionHierarchy: ROLE_ADMINISTRATOR > ROLE_CONTRIBUTOR > ROLE_USER
permissionDefinitions:
- permissionSet: ADMINISTRATOR
level: 100
mappings:
roleMappings:
local: ["application_admin"]
saml: ["generic-search-admins"]
- role: CONTRIBUTOR
- permissionSet: CONTRIBUTOR
level: 50
mappings:
roleMappings:
local: ["application_contributor"]
saml: ["generic-search-contributors"]
- role: USER
- permissionSet: USER
level: 10
mappings:
roleMappings:
local: ["application_user"]
saml: ["application_user"]
local:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment