Skip to content

Commit

Permalink
Merge branch 'development' into filesystem-cleanup-script-add-dates
Browse files Browse the repository at this point in the history
  • Loading branch information
ericenns authored Oct 12, 2023
2 parents ac253a1 + de36eab commit 6d04bba
Show file tree
Hide file tree
Showing 160 changed files with 2,965 additions and 1,204 deletions.
14 changes: 9 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
# Changelog

## [Unreleased]
* [Developer]: Added functionality to delete sequence files from file system when a sequence run is removed. [See PR 1468](https://github.com/phac-nml/irida/pull/1468)
* [Developer]: Added script to do initial cleanup of sequence files from file system. [See PR 1469](https://github.com/phac-nml/irida/pull/1469)
* [UI]: Add identifier to project drop-down on project synchronization page. See [PR 1474](https://github.com/phac-nml/irida/pull/1474)
* [Developer]: Added functionality to delete sequence files from file storage when removed from sample. [See PR 1476](https://github.com/phac-nml/irida/pull/1476)
* [Developer]: Added override flag that determines if files should be deleted from file storage. [See PR 1486](https://github.com/phac-nml/irida/pull/1486)
* [Developer]: Fixed flaky text in `PipelinesPhylogenomicsPageIT#testPageSetup` test. See [PR 1490](https://github.com/phac-nml/irida/pull/1492)
* [ALL]: Added LDAP/ADLDAP support.
* [Developer]: Added start and ends dates to filesystem clean up script. [See PR 1487](https://github.com/phac-nml/irida/pull/1487)

## [23.01.3] - 2023/05/09
* [Developer]: Fixed issue with metadata uploader removing exiting data. See [PR 1489](https://github.com/phac-nml/irida/pull/1489)
* [Developer]: Fixed issue with metadata uploader removing existing data. See [PR 1489](https://github.com/phac-nml/irida/pull/1489)

## [23.01.2] - 2023/04/17
* [UI]: Fixed bug that caused all metadata fields to be removed when single field was removed from a template. See [PR 1482](https://github.com/phac-nml/irida/pull/1482)
Expand Down Expand Up @@ -32,9 +39,6 @@
* [Developer]: Deprecated "/api/projects/{projectId}/samples/bySequencerId/{seqeuncerId}" in favour of "/api/projects/{projectId}/samples/bySampleName", which accepts a json property "sampleName"
* [Developer]: Fixed bug in setting a `default_sequencing_object and default_genome_assembly to `NULL` for a sample when the default sequencing object or genome assembly were removed. [See PR 1466](https://github.com/phac-nml/irida/pull/1466)
* [Developer]: Fixed bug preventing a `sample` with an analysis submission from being deleted. [See PR 1467](https://github.com/phac-nml/irida/pull/1467)
* [Developer]: Added functionality to delete sequence files from file system when a sequence run is removed. [See PR 1468](https://github.com/phac-nml/irida/pull/1468)
* [Developer]: Added script to do initial cleanup of sequence files from file system. [See PR 1469](https://github.com/phac-nml/irida/pull/1469)
* [UI]: Add identifier to project drop-down on project synchronization page. See [PR 1474](https://github.com/phac-nml/irida/pull/1474)

## [22.09.7] - 2023/01/24
* [UI]: Fixed bugs on NCBI Export page preventing the NCBI `submission.xml` file from being properly written. See [PR 1451](https://github.com/phac-nml/irida/pull/1451)
Expand Down
5 changes: 5 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,10 @@ dependencies {
}
implementation("org.springframework.boot:spring-boot-starter-validation")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.springframework.boot:spring-boot-starter-data-ldap")
implementation("org.springframework.security:spring-security-oauth2-authorization-server:0.3.1")
implementation("org.springframework.ldap:spring-ldap-core")
implementation("org.springframework.security:spring-security-ldap")
implementation("org.springframework.security:spring-security-oauth2-resource-server:5.7.3")
implementation("com.nimbusds:oauth2-oidc-sdk:10.1")
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
Expand Down Expand Up @@ -221,6 +224,8 @@ dependencies {
testImplementation("org.seleniumhq.selenium:selenium-support:4.4.0")
testImplementation("org.seleniumhq.selenium:selenium-chrome-driver:4.4.0")
testImplementation("org.mockftpserver:MockFtpServer:3.0.0")
testImplementation("org.springframework.ldap:spring-ldap-test")
testImplementation("com.unboundid:unboundid-ldapsdk:6.0.5")
}

tasks.register<Zip>("packageDistribution") {
Expand Down
1 change: 1 addition & 0 deletions doc/administrator/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,6 @@ <h1 class="page-heading">Administrator Documentation - Installing</h1>
<li><a href="web">Installing the IRIDA web interface</a></li>
<li><a href="faq">Installation FAQ</a></li>
<li><a href="upgrades">Upgrade Notes</a></li>
<li><a href="ldap">LDAP and Active Directory Setup and Migration</a></li>
</ul>
</div>
107 changes: 107 additions & 0 deletions doc/administrator/ldap/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
layout: default
search_title: "LDAP"
description: "LDAP and Active Directory Setup and Migration"
---

# LDAP / ADLDAP (Active Directory) Configuration

LDAP or ADLDAP (Active Directory) can be enabled by adding the appropriate properties to your conf file.

```
irida.administrative.authentication.mode=ldap
```
or
```
irida.administrative.authentication.mode=adldap
```

The default value is `local` and the authentication is handled by `bcrypt`

LDAP and ADLDAP require different configuration properties.

These lines contain example values, your ldap/adldap configuration will vary.
```
# LDAP config
irida.administrative.authentication.ldap.url=ldap://localhost:10389/
irida.administrative.authentication.ldap.base=dc=example,dc=com
irida.administrative.authentication.ldap.userdn=uid=admin,ou=system
irida.administrative.authentication.ldap.password=secret
irida.administrative.authentication.ldap.userdn_search_patterns=uid={0},ou=people
# Optional Argument. change this to 'follow' to handle referrals. See AbstractContextSource javadocs for more info
irida.administrative.authentication.ldap.set_referral=ignore
# Active Directory LDAP config
irida.administrative.authentication.adldap.url=ldaps://some.adldapurl.ca
# Optional Argument. Default `(&(objectClass=user)(userPrincipalName={0}))`
irida.administrative.authentication.adldap.searchfilter=
# Optional Argument, Can be empty depending on your Active Directory configuration
irida.administrative.authentication.adldap.rootdn=ou=USERS,ou=Group,dc=ADLDAPurl,dc=ca
# Optional Argument, Can be empty depending on your Active Directory configuration
irida.administrative.authentication.adldap.domain=adldapurl.ca
```

When LDAP/ADLDAP is enabled, IRIDA automatically creates a new user when they sign in for the first time. Additionally when Users sign in, some of their local user fields are updated to sync them to the values on the ldap/adldap server.

The following lines are required for both LDAP and ADLAP.

These lines contain example values, your ldap/adldap configuration will vary.

```
irida.administrative.authentication.ldap.userInfoEmail=mail
irida.administrative.authentication.ldap.userInfoFirstName=givenName
irida.administrative.authentication.ldap.userInfoLastName=sn
irida.administrative.authentication.ldap.userInfoPhoneNumber=telephoneNumber
```

# Use

When configured, users can sign in via their ldap/adldap credentials

Signing in for the first time will create a user account in the IRIDA system. These users can be seen via the admin panel, but are managed via ldap/adldap. If a user needs to have their password changed, fields updated or access revoked, this must be done via ldap/adldap.

Local users, including admin users and sequencer users are managed by the default model.

When login issues occur, appropriate error messages display to indicate if authentication failed via ldap/adldap, server connectivity, or local authentication failed.

# Verify Authentication

To verify that authentication is working as expected, you should create a ldap/adldap user and attempt sign in.

You should be able to sign in and a new IRIDA user account will be created for you.

# Migration

Migration of local user accounts to ldap/adldap authentication requires you to manually update IRIDA's SQL `user` and `user_AUD` tables.

Please read these sections carefully.

### Automatic Changes:

When IRIDA is updated to the latest version, an additional column `user_type` is added to `user` and `user_AUD` SQL tables.

The `user_type` column is not `nullable` and accepts the values `TYPE_LOCAL` or `TYPE_DOMAIN`.
* `TYPE_LOCAL`: Authentication will be handled by the default `bcrypt` authentication
* `TYPE_DOMAIN`: Authentication will be handled by the configured ldap/adldap authentication

The `user_type` column for all existing `user` and `user_AUD` rows are automatically set to `TYPE_LOCAL` during the version update.

### Verify and/or Change `username` Fields.

To migrate these existing accounts, first verify that the `username` field needs to match the configured search pattern identifier

Using the above configuration examples:
* LDAP: `uid={0},ou=people` will expect the local `username` value to match the ldap `uid` field.
* ADLDAP: `(&(objectClass=user)(userPrincipalName={0}))` will expect the local `username` value to match the adldap `userPrincipalName` field

These fields will vary depending on your ldap/adldap configuration

For each of the accounts that do not match, you will need to update the `username` column on both the `user` and `user_AUD` SQL tables.

### Switching Users to LDAP/ADLDAP

Migrating existing local users to domain authentication is done by changing the `user_type` field to `TYPE_DOMAIN` on both the `user` and `user_AUD` table.

The sequencer user accounts, denoted by `system_role="ROLE_SEQUENCER"` on the `user`/`user_AUD` tables should not be migrated.

### Note: The original Administrator user `admin` should not be changed to `TYPE_DOMAIN`
9 changes: 9 additions & 0 deletions scripts/clean_tmp_irida_dir.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/sh

# This is intended to only be run during development, so that uploaded data can be cleared easily.
# This must be run with sudo as it affects /tmp/

rm -r /tmp/irida/sequence-files/*
rm -r /tmp/irida/output-files/*
rm -r /tmp/irida/reference-files/*
rm -r /tmp/irida/assembly-files/*
32 changes: 32 additions & 0 deletions scripts/example_ldap_for_apache_directory_studio.ldif
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
dn: ou=people,dc=example,dc=com
objectclass: top
objectclass: organizationalUnit
ou: people

dn: uid=jwick,ou=people,dc=example,dc=com
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: John Wick
sn: Wick
uid: jwick
givenName: John
mail: [email protected]
telephoneNumber: 169-637-3314
userPassword: Password1!

dn: uid=jdoe,ou=people,dc=example,dc=com
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Jane Doe
sn: Doe
description: 19650324000000Z
employeeNumber: 12
givenName: Jane
mail: [email protected]
telephoneNumber: 907-547-9114
uid: jdoe
userPassword: Password1
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,52 @@

import java.util.List;

import ca.corefacility.bioinformatics.irida.security.permissions.BasePermission;
import ca.corefacility.bioinformatics.irida.security.permissions.IridaPermissionEvaluator;
import com.google.common.base.Joiner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.Ordered;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
import org.springframework.security.authentication.AnonymousAuthenticationProvider;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;

import ca.corefacility.bioinformatics.irida.repositories.user.UserRepository;
import ca.corefacility.bioinformatics.irida.security.IridaPostAuthenicationChecker;
import ca.corefacility.bioinformatics.irida.security.PasswordExpiryChecker;
import ca.corefacility.bioinformatics.irida.security.permissions.BasePermission;
import ca.corefacility.bioinformatics.irida.security.permissions.IridaPermissionEvaluator;

import com.google.common.base.Joiner;

/**
* Configuration for IRIDA's spring security modules
*/
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, order = IridaApiSecurityConfig.METHOD_SECURITY_ORDER)
@ComponentScan(basePackages = "ca.corefacility.bioinformatics.irida.security")
@Import({ IridaAuthenticationSecurityConfig.class })
public class IridaApiSecurityConfig extends GlobalMethodSecurityConfiguration {

@Autowired(required = false)
@Qualifier("ldapAuthenticationProvider")
private AuthenticationProvider ldapAuthenticationProvider;

@Autowired(required = false)
@Qualifier("activeDirectoryLdapAuthenticationProvider")
private AuthenticationProvider activeDirectoryLdapAuthenticationProvider;

@Autowired
@Qualifier("defaultAuthenticationProvider")
private AuthenticationProvider defaultAuthenticationProvider;

@Value("${irida.administrative.authentication.mode}")
private String authenticationMode;

public static final int METHOD_SECURITY_ORDER = Ordered.LOWEST_PRECEDENCE;

private static final String ANONYMOUS_AUTHENTICATION_KEY = "anonymousTokenAuthProvider";
Expand All @@ -50,9 +60,6 @@ public class IridaApiSecurityConfig extends GlobalMethodSecurityConfiguration {

private static final String ROLE_HIERARCHY = Joiner.on('\n').join(ROLE_HIERARCHIES);

@Value("${security.password.expiry}")
private int passwordExpiryInDays = -1;

/**
* Loads all of the {@link BasePermission} sub-classes found in the security package during component scan.
* {@link BasePermission} classes are used in {@link @PreAuthorize} annotations for verifying that a user has
Expand All @@ -61,9 +68,6 @@ public class IridaApiSecurityConfig extends GlobalMethodSecurityConfiguration {
@Autowired
private List<BasePermission<?>> basePermissions;

@Autowired
private UserRepository userRepository;

@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
Expand All @@ -78,8 +82,15 @@ protected MethodSecurityExpressionHandler createExpressionHandler() {

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userRepository).passwordEncoder(passwordEncoder());
auth.authenticationProvider(authenticationProvider()).authenticationProvider(anonymousAuthenticationProvider());
// Order of auth providers matters.
// Default DAO must be first to allow admin/local sign-in if ldap servers are unresponsive.
auth.authenticationProvider(defaultAuthenticationProvider);
if (authenticationMode.equals("ldap")) {
auth.authenticationProvider(ldapAuthenticationProvider);
} else if (authenticationMode.equals("adldap")) {
auth.authenticationProvider(activeDirectoryLdapAuthenticationProvider);
}
auth.authenticationProvider(anonymousAuthenticationProvider());
}

/**
Expand All @@ -94,41 +105,11 @@ private AuthenticationProvider anonymousAuthenticationProvider() {
return anonymousAuthenticationProvider;
}

@Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userRepository);
authenticationProvider.setPasswordEncoder(passwordEncoder());

/*
Expire a user's password after the given number of days and force them to change it.
*/
if (passwordExpiryInDays != -1) {
authenticationProvider
.setPreAuthenticationChecks(new PasswordExpiryChecker(userRepository, passwordExpiryInDays));
}

/*
* After a user has been authenticated, we want to allow them to change
* their password if the password is expired. The
* {@link IgnoreExpiredCredentialsForPasswordChangeChecker} allows
* authenticated users with expired credentials to invoke one method, the
* {@link UserService#changePassword(Long, String)} method.
*/
authenticationProvider.setPostAuthenticationChecks(new IridaPostAuthenicationChecker());
return authenticationProvider;
}

@Bean(name = "userAuthenticationManager")
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

/**
* Default {@link DefaultWebSecurityExpressionHandler}. This is used by Thymeleaf's Spring Security plugin, and
* isn't actually used anywhere in the back-end, but it needs to be in the back-end configuration classes because
Expand Down
Loading

0 comments on commit 6d04bba

Please sign in to comment.