Skip to content

Commit

Permalink
Merge pull request #231 from it-at-m/168-implementierung-wahlkonfigur…
Browse files Browse the repository at this point in the history
…ation

168 implementierung wahlkonfiguration
  • Loading branch information
MrSebastian committed May 31, 2024
2 parents 8ab601b + 380166a commit 10cbf2e
Show file tree
Hide file tree
Showing 59 changed files with 2,570 additions and 68 deletions.
10 changes: 6 additions & 4 deletions docs/src/technik/development/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@ flowchart LR

### Benutzer

| Name | Passwort | Beschreibung |
| --- | --- | --- |
| keycloak_test | test | Ein Benutzer ohne weitere Rechte |
| wls_all | test | Ein Benutzer mit allen Rechten |
| Name | Passwort | Beschreibung |
| --- | --- |-----------------------------------------------------------------------|
| keycloak_test | test | Ein Benutzer ohne weitere Rechte |
| wls_all | test | Ein Benutzer mit allen Rechten |
| wls_all_bwb | test | Ein Benutzer mit allen Rechten mit der WahlbezirksArt BWB (Briefwahl) |
| wls_all_uwb | test | Ein Benutzer mit allen Rechten mit der WahlbezirksArt UWB (Urnenwahl) |

### Beispiel-Requests

Expand Down
5 changes: 2 additions & 3 deletions stack/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ services:
## Keycloak
wls-keycloak:
container_name: wls-keycloak
image: quay.io/keycloak/keycloak:24.0.4
image: quay.io/keycloak/keycloak:20.0.5
command:
- start-dev
- start-dev --http-relative-path /auth
depends_on:
- wls-db-postgres-keycloak
environment:
Expand All @@ -36,7 +36,6 @@ services:
- KC_DB_URL=jdbc:postgresql://wls-db-postgres-keycloak:5432/${KEYCLOAK_DB}
- KC_DB_USERNAME=${KEYCLOAK_DB_USER}
- KC_DB_PASSWORD=${KEYCLOAK_DB_PASSWORD}
- KC_HTTP_RELATIVE_PATH=auth
ports:
- 8100:8080
networks:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
id: add authorities infomanagement konfiguration
author: MrSebastian
realm: ${SSO_REALM}
changes:
- addRole:
name: Infomanagement_READ_Konfiguration
clientRole: true
clientId: ${SSO_CLIENT_ID}
- addRole:
name: Infomanagement_WRITE_Konfiguration
clientRole: true
clientId: ${SSO_CLIENT_ID}
- addRole:
name: Infomanagement_DELETE_Konfiguration
clientRole: true
clientId: ${SSO_CLIENT_ID}
- addRole:
name: Infomanagement_BUSINESSACTION_GetKonfiguration
clientRole: true
clientId: ${SSO_CLIENT_ID}
- addRole:
name: Infomanagement_BUSINESSACTION_GetKonfigurationen
clientRole: true
clientId: ${SSO_CLIENT_ID}
- addRole:
name: Infomanagement_BUSINESSACTION_PostKonfiguration
clientRole: true
clientId: ${SSO_CLIENT_ID}

- assignRoleToGroup:
group: allInfomanagementAuthorities
role: Infomanagement_READ_Konfiguration
clientId: ${SSO_CLIENT_ID}
- assignRoleToGroup:
group: allInfomanagementAuthorities
role: Infomanagement_WRITE_Konfiguration
clientId: ${SSO_CLIENT_ID}
- assignRoleToGroup:
group: allInfomanagementAuthorities
role: Infomanagement_DELETE_Konfiguration
clientId: ${SSO_CLIENT_ID}
- assignRoleToGroup:
group: allInfomanagementAuthorities
role: Infomanagement_BUSINESSACTION_GetKonfiguration
clientId: ${SSO_CLIENT_ID}
- assignRoleToGroup:
group: allInfomanagementAuthorities
role: Infomanagement_BUSINESSACTION_GetKonfigurationen
clientId: ${SSO_CLIENT_ID}
- assignRoleToGroup:
group: allInfomanagementAuthorities
role: Infomanagement_BUSINESSACTION_PostKonfiguration
clientId: ${SSO_CLIENT_ID}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
id: add authorities infomanagement kennbuchstaben
author: MrSebastian
realm: ${SSO_REALM}
changes:
- addRole:
name: Infomanagement_BUSINESSACTION_GetKennbuchstabenListen
clientRole: true
clientId: ${SSO_CLIENT_ID}

- assignRoleToGroup:
group: allInfomanagementAuthorities
role: Infomanagement_BUSINESSACTION_GetKennbuchstabenListen
clientId: ${SSO_CLIENT_ID}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
id: add user attribute mapper wahlbezirksart
author: MrSebastian
realm: ${SSO_REALM}
changes:
# maps user attribute wahlbezirksArt to a claim wahlbezirksArt
- addClientUserAttributeMapper:
clientId: ${SSO_CLIENT_ID}
name: wahlbezirksArt
userAttribute: wahlbezirksArt
claimName: wahlbezirksArt
addToUserInfo: true
addToAccessToken: true
47 changes: 47 additions & 0 deletions stack/keycloak/migration/add-wahlbezirksart-to-user.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
id: add wahlbezirksart to user
author: MrSebastian
realm: ${SSO_REALM}
changes:
- addUserAttribute:
name: wls_all
attributeName: wahlbezirksArt
attributeValues:
- UWB

- addUser:
name: wls_all_uwb
lastName: all
firstName: wls_uwb
enabled: true
emailVerified: true
email: wls_all_uwb@example.com
attributes:
user_name:
- wls_all_uwb
wahlbezirksArt:
- UWB
groups:
- allBroadcastAuthorities
- allInfomanagementAuthorities
- updateUserPassword:
name: wls_all_uwb
password: "test"

- addUser:
name: wls_all_bwb
lastName: all
firstName: wls_bwb
enabled: true
emailVerified: true
email: wls_all_bwb@example.com
attributes:
user_name:
- wls_all_bwb
wahlbezirksArt:
- BWB
groups:
- allBroadcastAuthorities
- allInfomanagementAuthorities
- updateUserPassword:
name: wls_all_bwb
password: "test"
6 changes: 5 additions & 1 deletion stack/keycloak/migration/keycloak-changelog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,8 @@ includes:
- path: create-and-assign-group-all-wahlvorbereitung.yml
- path: add-authorities-wahlvorbereitung-urnenwahlvorbereitung.yml
- path: add_authorities-briefwahl-wahlbriefdaten.yml
- path: add-authorities-wahlvorbereitung-waehlerverzeichnis.yml
- path: add-authorities-wahlvorbereitung-waehlerverzeichnis.yml
- path: add-authorities-infomanagement-konfiguration.yml
- path: add-user-attribute-mapper-wahlbezirks-art.yml
- path: add-wahlbezirksart-to-user.yml
- path: add-authority-infomanagement-kennbuchstaben.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package de.muenchen.oss.wahllokalsystem.infomanagementservice.common.security;

import java.util.Optional;
import org.springframework.context.annotation.Profile;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;

@Component
@Profile("no-security")
public class AnonymousHandler implements AuthenticationHandler {
@Override
public boolean canHandle(Authentication authentication) {
return authentication instanceof AnonymousAuthenticationToken;
}

@Override
public Optional<String> getDetail(String detailKey, Authentication authentication) {
return Optional.empty();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package de.muenchen.oss.wahllokalsystem.infomanagementservice.common.security;

import java.util.Optional;
import org.springframework.security.core.Authentication;

public interface AuthenticationHandler {

boolean canHandle(Authentication authentication);

Optional<String> getDetail(String detailKey, Authentication authentication);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package de.muenchen.oss.wahllokalsystem.infomanagementservice.common.security;

import java.util.Optional;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.stereotype.Component;

@Component
public class JWTHandler implements AuthenticationHandler {

@Override
public boolean canHandle(final Authentication authentication) {
return authentication instanceof JwtAuthenticationToken;
}

public Optional<String> getDetail(final String detailKey, final Authentication authentication) {
if (authentication instanceof JwtAuthenticationToken jwtToken) {
return Optional.ofNullable(jwtToken.getToken().getClaimAsString(detailKey));
} else {
return Optional.empty();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
AntPathRequestMatcher.antMatcher("/actuator/metrics"),
AntPathRequestMatcher.antMatcher("/v3/api-docs/**"),
AntPathRequestMatcher.antMatcher("/swagger-ui/**"),
AntPathRequestMatcher.antMatcher("/businessActions/loginCheck/**"))
AntPathRequestMatcher.antMatcher("/businessActions/loginCheck/**"),
AntPathRequestMatcher.antMatcher("/businessActions/konfigurationUnauthorized/**"))
.permitAll())
.authorizeHttpRequests((requests) -> requests.requestMatchers("/**")
.authenticated())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package de.muenchen.oss.wahllokalsystem.infomanagementservice.domain.konfiguration;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Indexed;

@Entity
@Indexed
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Konfiguration {

@Id
@NotNull
@Size(max = 255)
private String schluessel;

@Size(max = 1024)
private String wert;

@Size(max = 1024)
private String beschreibung;

@Size(max = 1024)
private String standardwert;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package de.muenchen.oss.wahllokalsystem.infomanagementservice.domain.konfiguration;

import java.util.List;
import java.util.Optional;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.lang.NonNull;
import org.springframework.security.access.prepost.PreAuthorize;

public interface KonfigurationRepository extends CrudRepository<Konfiguration, String> {

String CACHE = "KonfigurationCACHE";

@Override
@PreAuthorize("hasAuthority('Infomanagement_READ_Konfiguration')")
@NonNull
List<Konfiguration> findAll();

@Override
@Cacheable(value = CACHE, key = "#p0")
@PreAuthorize("hasAuthority('Infomanagement_READ_Konfiguration')")
@NonNull
Optional<Konfiguration> findById(@NonNull String key);

@Override
@CachePut(value = CACHE, key = "#p0.schluessel")
@PreAuthorize("hasAuthority('Infomanagement_WRITE_Konfiguration')")
@NonNull
<S extends Konfiguration> S save(@NonNull S konfiguration);

@Override
@CacheEvict(value = CACHE, key = "#p0")
@PreAuthorize("hasAuthority('Infomanagement_DELETE_Konfiguration')")
void deleteById(@NonNull String key);

@Override
@CacheEvict(value = CACHE, key = "#p0.schluessel")
@PreAuthorize("hasAuthority('Infomanagement_DELETE_Konfiguration')")
void delete(@NonNull Konfiguration entity);

@Override
@CacheEvict(value = CACHE, allEntries = true)
@PreAuthorize("hasAuthority('Infomanagement_DELETE_Konfiguration')")
void deleteAll(@NonNull Iterable<? extends Konfiguration> entities);

@Override
@CacheEvict(value = CACHE, allEntries = true)
@PreAuthorize("hasAuthority('Infomanagement_DELETE_Konfiguration')")
void deleteAll();

@Query("SELECT k FROM Konfiguration k WHERE k.schluessel = 'FRUEHESTE_LOGIN_UHRZEIT'")
Optional<Konfiguration> getFruehesteLoginUhrzeit();

@Query("SELECT k FROM Konfiguration k WHERE k.schluessel = 'SPAETESTE_LOGIN_UHRZEIT'")
Optional<Konfiguration> getSpaetesteLoginUhrzeit();

@Query("SELECT k FROM Konfiguration k WHERE k.schluessel = 'WILLKOMMENSTEXT'")
Optional<Konfiguration> getWillkommenstext();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package de.muenchen.oss.wahllokalsystem.infomanagementservice.exception;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ExceptionConstants {
public static final ExceptionDataWrapper DELETE_KONFIGURIERTERWAHLTAG_NOT_DELETEABLE = new ExceptionDataWrapper("105",
"deleteKonfigurierterWahltag: Der konfigurierte Wahltag konnte nicht gelöscht werden.");
public static final ExceptionDataWrapper POST_KONFIGURIERTERWAHLTAG_PARAMETER_UNVOLLSTAENDIG = new ExceptionDataWrapper("100",
"postKonfigurierterWahltag: Suchkriterien unvollständig.");
public static final ExceptionDataWrapper DELETE_KONFIGURIERTERWAHLTAG_PARAMETER_UNVOLLSTAENDIG = new ExceptionDataWrapper("104",
"deleteKonfigurierterWahltag: Suchkriterien unvollständig.");
public static final ExceptionDataWrapper POSTKONFIGURATION_NOT_SAVEABLE = new ExceptionDataWrapper("101",
"postKonfiguration: Die Konfiguration konnte nicht gespeichert werden.");
public static final ExceptionDataWrapper GETKENNBUCHSTABENLISTEN_KONFIGURATION_NOT_FOUND = new ExceptionDataWrapper("103",
"getKennbuchstabenListen: Es wurden keine Kennbuchstaben gefunden.");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package de.muenchen.oss.wahllokalsystem.infomanagementservice.exception;

import de.muenchen.oss.wahllokalsystem.wls.common.exception.errorhandler.AbstractExceptionHandler;
import de.muenchen.oss.wahllokalsystem.wls.common.exception.rest.model.DTOMapper;
import de.muenchen.oss.wahllokalsystem.wls.common.exception.rest.model.WlsExceptionDTO;
import de.muenchen.oss.wahllokalsystem.wls.common.exception.util.ServiceIDFormatter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler extends AbstractExceptionHandler {

private final ServiceIDFormatter serviceIDFormatter;

public GlobalExceptionHandler(final ServiceIDFormatter serviceIDFormatter, final DTOMapper dtoMapper) {
super(dtoMapper);
this.serviceIDFormatter = serviceIDFormatter;
}

@ExceptionHandler
public ResponseEntity<WlsExceptionDTO> handleThrowables(final Throwable throwable) {
log.info("handling throwable", throwable);
return createResponse(getWahlExceptionDTO(throwable));
}

@Override
protected String getService() {
return serviceIDFormatter.getId();
}
}
Loading

0 comments on commit 10cbf2e

Please sign in to comment.