Skip to content

Commit

Permalink
add user roles
Browse files Browse the repository at this point in the history
  • Loading branch information
KochTobi committed Apr 8, 2024
1 parent cec2de4 commit 0fd7ffc
Show file tree
Hide file tree
Showing 11 changed files with 200 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class AsyncDownloadConfig implements AsyncConfigurer {
public AsyncTaskExecutor getAsyncExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setCorePoolSize(2);
threadPoolTaskExecutor.setMaxPoolSize(2);
threadPoolTaskExecutor.setMaxPoolSize(5);
threadPoolTaskExecutor.setQueueCapacity(200);
threadPoolTaskExecutor.setThreadNamePrefix("download - ");
threadPoolTaskExecutor.initialize();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public SecurityFilterChain apiFilterChain(HttpSecurity http,
.addFilterAt(tokenAuthenticationFilter, BasicAuthenticationFilter.class)
.authorizeHttpRequests(authorizedRequest ->
authorizedRequest
.requestMatchers("/measurements/{measurementId}")
.requestMatchers("measurements/{measurementId}")
.access(anyOf(
requestAuthorizationManagerFactory.spel(
"hasPermission(#measurementId, 'qbic.measurement', 'READ')")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
import java.io.OutputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Optional;
import java.util.UUID;
import javax.swing.text.html.Option;
import life.qbic.data_download.measurements.api.DataFile;
import life.qbic.data_download.measurements.api.MeasurementData;
import life.qbic.data_download.measurements.api.MeasurementDataProvider;
Expand All @@ -26,6 +28,7 @@
import life.qbic.data_download.util.zip.manipulation.BufferedZippingFunctions;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.context.SecurityContextHolder;
Expand All @@ -39,15 +42,18 @@ public class DownloadController {

private final MeasurementDataProvider measurementDataProvider;
private final MeasurementDataReaderFactory measurementDataReaderFactory;
private final int downloadBufferSize;

private static final Logger log = getLogger(DownloadController.class);

public DownloadController(
@Qualifier("measurementDataProvider") MeasurementDataProvider measurementDataProvider,
@Qualifier("measurementDataReaderFactory") MeasurementDataReaderFactory measurementDataReaderFactory
) {
@Qualifier("measurementDataReaderFactory") MeasurementDataReaderFactory measurementDataReaderFactory,
@Value("${server.memory.download.buffer}") Integer downloadBufferSize) {
this.measurementDataProvider = measurementDataProvider;
this.measurementDataReaderFactory = measurementDataReaderFactory;
this.downloadBufferSize = Optional.ofNullable(downloadBufferSize)
.orElse(BufferedZippingFunctions.DEFAULT_BUFFER_SIZE);
}


Expand Down Expand Up @@ -107,7 +113,7 @@ private void writeDataToStream(MeasurementId measurementId, OutputStream outputS
new FileTimes(file.fileInfo().registrationMillis(), -1,
file.fileInfo().lastModifiedMillis()));

BufferedZippingFunctions.addToZip(zippedStream, zipEntryFileInfo, file.inputStream(), BufferedZippingFunctions.DEFAULT_BUFFER_SIZE);
BufferedZippingFunctions.addToZip(zippedStream, zipEntryFileInfo, file.inputStream(), downloadBufferSize);
}
} catch (IOException e) {
throw new GlobalException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.transaction.annotation.Transactional;

/**
* An {@link AuthenticationProvider} capable of authenticating a
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
CREATE TABLE acl_sid
(
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
principal BOOLEAN NOT NULL,
sid VARCHAR(100) NOT NULL,
UNIQUE KEY unique_acl_sid (sid, principal)
) ENGINE = InnoDB;

CREATE TABLE acl_class
(
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
class VARCHAR(100) NOT NULL,
class_id_type VARCHAR(100) NOT NULL,
UNIQUE KEY uk_acl_class (class)
) ENGINE = InnoDB;

CREATE TABLE acl_object_identity
(
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
object_id_class BIGINT UNSIGNED NOT NULL,
object_id_identity VARCHAR(36) NOT NULL,
parent_object BIGINT UNSIGNED,
owner_sid BIGINT UNSIGNED,
entries_inheriting BOOLEAN NOT NULL,
UNIQUE KEY uk_acl_object_identity (object_id_class, object_id_identity),
CONSTRAINT fk_acl_object_identity_parent FOREIGN KEY (parent_object) REFERENCES acl_object_identity (id),
CONSTRAINT fk_acl_object_identity_class FOREIGN KEY (object_id_class) REFERENCES acl_class (id),
CONSTRAINT fk_acl_object_identity_owner FOREIGN KEY (owner_sid) REFERENCES acl_sid (id)
) ENGINE = InnoDB;

CREATE TABLE acl_entry
(
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
acl_object_identity BIGINT UNSIGNED NOT NULL,
ace_order INTEGER NOT NULL,
sid BIGINT UNSIGNED NOT NULL,
mask INTEGER UNSIGNED NOT NULL,
granting BOOLEAN NOT NULL,
audit_success BOOLEAN NOT NULL DEFAULT true,
audit_failure BOOLEAN NOT NULL,
UNIQUE KEY unique_acl_entry (acl_object_identity, ace_order),
CONSTRAINT fk_acl_entry_object FOREIGN KEY (acl_object_identity) REFERENCES acl_object_identity (id),
CONSTRAINT fk_acl_entry_acl FOREIGN KEY (sid) REFERENCES acl_sid (id) ON DELETE CASCADE
) ENGINE = InnoDB;

INSERT INTO acl_class(id, class, class_id_type)
VALUES (1, 'life.qbic.projectmanagement.domain.model.project.Project', 'java.lang.String');
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
INSERT INTO roles(id, name, description)
VALUES (1, 'ADMIN', 'Full administration of the application'),
(2, 'USER', 'Standard user of the application'),
(3, 'PROJECT_MANAGER', 'Manages projects at QBiC')
;
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinTable;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import org.springframework.data.annotation.ReadOnlyProperty;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
Expand All @@ -20,25 +25,25 @@
public class QBiCUserDetails implements UserDetails {

@Id
@ReadOnlyProperty
@Column(name = "id")
@ReadOnlyProperty
private String id;

@OneToMany(fetch = FetchType.EAGER, mappedBy = "user")
@ReadOnlyProperty
private Set<UserRole> userRoles;

@Column(nullable = false, name = "active")
@ReadOnlyProperty
private boolean active;

public String id() {
return id;
}

public boolean active() {
return active;
}

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return List.of();
return userRoles.stream().map(UserRole::role).toList();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package life.qbic.data_download.rest.security.jpa.user;

import static java.util.Objects.requireNonNull;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.util.Optional;
import java.util.StringJoiner;
import org.springframework.data.annotation.ReadOnlyProperty;
import org.springframework.security.core.GrantedAuthority;

@Entity
@Table(name = "roles")
public class Role implements GrantedAuthority {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
@ReadOnlyProperty
private long id;

@Column(name = "name")
@ReadOnlyProperty
private String name;

@Column(name = "description")
@ReadOnlyProperty
private String description;


protected Role() {
}

protected Role(long id, String name, String description) {
this.id = id;
this.name = name;
this.description = description;
}

public String name() {
requireNonNull(this.name);
return name;
}

public Optional<String> description() {
return Optional.ofNullable(description);
}

@Override
public String toString() {
return new StringJoiner(", ", Role.class.getSimpleName() + "[", "]")
.add("id='" + id + "'")
.add("name='" + name + "'")
.add("description='" + description + "'")
.toString();
}

@Override
public String getAuthority() {
return "ROLE_" + name();
}

public long getId() {
return id;
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else {
return obj instanceof GrantedAuthority && this.getAuthority()
.equals(((GrantedAuthority) obj).getAuthority());
}
}

@Override
public int hashCode() {
return getAuthority().hashCode();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

import java.util.Optional;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.Repository;

public interface UserDetailsRepository extends CrudRepository<QBiCUserDetails, Integer> {
public interface UserDetailsRepository extends Repository<QBiCUserDetails, Integer> {
Optional<QBiCUserDetails> findById(String id);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package life.qbic.data_download.rest.security.jpa.user;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.io.Serializable;
import org.springframework.data.annotation.ReadOnlyProperty;

@Entity
@Table(name = "user_role")
public class UserRole implements Serializable {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
@ReadOnlyProperty
private long id;

@ManyToOne(optional = false)
@JoinColumn(name = "userId", nullable = false)
@ReadOnlyProperty
private QBiCUserDetails user;

@ManyToOne(optional = false)
@JoinColumn(name = "roleId")
@ReadOnlyProperty
private Role role;

public Role role() {
return role;
}
}
1 change: 1 addition & 0 deletions rest-api/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ qbic.access-token.iteration-count=${ACCESS_TOKEN_ITERATIONS:100000}

### server settings
server.download.token-name=${TOKEN_NAME:Bearer}
server.memory.download.buffer=${DOWNLOAD_BUFFER:}
server.port=${SERVER_PORT:8090}
server.servlet.context-path=${SERVER_CONTEXT_PATH:}

Expand Down

0 comments on commit 0fd7ffc

Please sign in to comment.