migrate from CAS to Oauth2-JWT Auth (#197)
Co-authored-by: Michael Hoennig <michael@hoennig.de> Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/197 Reviewed-by: Marc Sandlus <marc.sandlus@hostsharing.net>
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
package net.hostsharing.hsadminng.config;
|
||||
|
||||
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityScheme;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import static net.hostsharing.hsadminng.config.JwtFakeBearer.RSA_KEY;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
// securitySchemes should work in OpenAPI yaml, but the Spring templates seem not to support it
|
||||
@SecurityScheme(
|
||||
name = "bearerAuth",
|
||||
type = SecuritySchemeType.HTTP,
|
||||
scheme = "bearer",
|
||||
bearerFormat = "JWT"
|
||||
)
|
||||
public abstract class BaseWebSecurityConfig {
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain(final HttpSecurity http) throws Exception {
|
||||
return http
|
||||
.authorizeHttpRequests(authorize -> authorize
|
||||
.requestMatchers(
|
||||
// only list endpoints implemented in libraries here
|
||||
"/swagger-ui/**",
|
||||
"/v3/api-docs/**",
|
||||
"/actuator/**",
|
||||
"/fake-jwt/**"
|
||||
// otherwise use @PreAuthorize annotation at the controller class / endpoint method level
|
||||
).permitAll()
|
||||
.requestMatchers("/api/**").permitAll() // controlled at method level
|
||||
.anyRequest().denyAll()
|
||||
)
|
||||
.oauth2ResourceServer(oauth ->
|
||||
oauth.jwt(Customizer.withDefaults()))
|
||||
.csrf(AbstractHttpConfigurer::disable)
|
||||
.cors(AbstractHttpConfigurer::disable)
|
||||
.exceptionHandling(exception -> exception
|
||||
.authenticationEntryPoint((request, response, authException) ->
|
||||
// For unknown reason Spring security returns 403 FORBIDDEN for a BadCredentialsException.
|
||||
// But it should return 401 UNAUTHORIZED.
|
||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED)
|
||||
)
|
||||
)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Value("${spring.security.oauth2.resourceserver.jwt.jwk-set-uri:http://localhost:${server.port}/fake-jwt/.well-known/jwks.json}")
|
||||
private String jwkSetUri;
|
||||
|
||||
@Bean
|
||||
@Profile("!fake-jwt")
|
||||
public JwtDecoder jwtDecoder() {
|
||||
return NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Profile("fake-jwt")
|
||||
@SneakyThrows
|
||||
public JwtDecoder fakeJwtDecoder() {
|
||||
// For fake-jwt profile, use the same RSA key as JwtFakeBearer
|
||||
return NimbusJwtDecoder.withPublicKey(RSA_KEY.toRSAPublicKey()).build();
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package net.hostsharing.hsadminng.config;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
// Do NOT use @Component (or similar) here, this would register the filter directly.
|
||||
// But we need to register it in the SecurityFilterChain created by WebSecurityConfig.
|
||||
// The bean gets created in net.hostsharing.hsadminng.config.WebSecurityConfig.authenticationFilter.
|
||||
@AllArgsConstructor
|
||||
public class CasAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
private CasAuthenticator authenticator;
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
protected void doFilterInternal(
|
||||
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) {
|
||||
|
||||
if (request.getHeader("authorization") != null) {
|
||||
final var authenticatedRequest = new AuthenticatedHttpServletRequestWrapper(request);
|
||||
final var currentSubject = authenticator.authenticate(request);
|
||||
final var authentication = new UsernamePasswordAuthenticationToken(currentSubject, null, null);
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
filterChain.doFilter(authenticatedRequest, response);
|
||||
} else {
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package net.hostsharing.hsadminng.config;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
public interface CasAuthenticator {
|
||||
|
||||
String authenticate(final HttpServletRequest httpRequest);
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package net.hostsharing.hsadminng.config;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
public class FakeCasAuthenticator implements CasAuthenticator {
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public String authenticate(final HttpServletRequest httpRequest) {
|
||||
return httpRequest.getHeader("Authorization").replaceAll("^Bearer ", "");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package net.hostsharing.hsadminng.config;
|
||||
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@RestController
|
||||
@Profile("fake-jwt")
|
||||
@NoSecurityRequirement
|
||||
@Slf4j
|
||||
public class FakeJwtController {
|
||||
|
||||
@PostMapping(value = "/fake-jwt/token", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
@Timed("app.config.jwt.token")
|
||||
public ResponseEntity<Map<String, Object>> token(
|
||||
@RequestParam String username,
|
||||
@RequestParam String password,
|
||||
@RequestParam(defaultValue = "openid profile") String scope) {
|
||||
|
||||
log.info("Fake JWT: Issuing token for user: {}", username);
|
||||
|
||||
// Accept any username/password for local testing
|
||||
String token = JwtFakeBearer.bearer(username).replace("Bearer ", "");
|
||||
|
||||
return ResponseEntity.ok(Map.of(
|
||||
"access_token", token,
|
||||
"token_type", "Bearer",
|
||||
"expires_in", 3600,
|
||||
"scope", scope
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -11,18 +11,16 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
||||
|
||||
|
||||
@Configuration
|
||||
public class JsonObjectMapperConfiguration {
|
||||
|
||||
public static ObjectMapper build() {
|
||||
return new JsonObjectMapperConfiguration().customObjectMapper().build();
|
||||
return new JsonObjectMapperConfiguration().customObjectMapper();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public Jackson2ObjectMapperBuilder customObjectMapper() {
|
||||
// HOWTO: add JSON converters and specify other JSON mapping configurations
|
||||
public ObjectMapper customObjectMapper() {
|
||||
return new Jackson2ObjectMapperBuilder()
|
||||
.modules(new JsonNullableModule(), new JavaTimeModule())
|
||||
.featuresToEnable(
|
||||
@@ -30,6 +28,7 @@ public class JsonObjectMapperConfiguration {
|
||||
DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS,
|
||||
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
|
||||
)
|
||||
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package net.hostsharing.hsadminng.config;
|
||||
|
||||
import com.nimbusds.jose.JWSAlgorithm;
|
||||
import com.nimbusds.jose.JWSHeader;
|
||||
import com.nimbusds.jose.crypto.RSASSASigner;
|
||||
import com.nimbusds.jose.jwk.RSAKey;
|
||||
import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
|
||||
import com.nimbusds.jwt.JWTClaimsSet;
|
||||
import com.nimbusds.jwt.SignedJWT;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.val;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Provides a fake JWT bearer generator.
|
||||
*/
|
||||
public class JwtFakeBearer {
|
||||
|
||||
public static final RSAKey RSA_KEY = generateRSAKey(2048, "test-key");
|
||||
|
||||
@SneakyThrows
|
||||
public static String bearer(final String subject) {
|
||||
val claims = new JWTClaimsSet.Builder()
|
||||
.subject(subject)
|
||||
.issuer("http://test-issuer")
|
||||
.audience("api")
|
||||
.expirationTime(new Date(System.currentTimeMillis() + 3600_000))
|
||||
.build();
|
||||
|
||||
val signed = new SignedJWT(
|
||||
new JWSHeader.Builder(JWSAlgorithm.RS256)
|
||||
.keyID(RSA_KEY.getKeyID()).build(), claims);
|
||||
signed.sign(new RSASSASigner(RSA_KEY.toPrivateKey()));
|
||||
return "Bearer " + signed.serialize();
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private static RSAKey generateRSAKey(final int size, final String keyID) {
|
||||
return new RSAKeyGenerator(size).keyID(keyID).generate();
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
package net.hostsharing.hsadminng.config;
|
||||
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.w3c.dom.Document;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import java.io.IOException;
|
||||
|
||||
// HOWTO add logger
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class RealCasAuthenticator implements CasAuthenticator {
|
||||
|
||||
@Value("${hsadminng.cas.server}")
|
||||
private String casServerUrl;
|
||||
|
||||
@Value("${hsadminng.cas.service}")
|
||||
private String serviceUrl;
|
||||
|
||||
private final MessageTranslator messageTranslator;
|
||||
|
||||
private final RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
@Timed("app.cas.authenticate")
|
||||
public String authenticate(final HttpServletRequest httpRequest) {
|
||||
final var ticket = httpRequest.getHeader("authorization").replaceAll("^Bearer ", "");
|
||||
final var serviceTicket = ticket.startsWith("TGT-")
|
||||
? fetchServiceTicket(ticket)
|
||||
: ticket;
|
||||
final var userName = extractUserName(verifyServiceTicket(serviceTicket));
|
||||
// HOWTO log some message for a certain log level (trace, debug, info, warn, error)
|
||||
log.debug("CAS-user: {}", userName);
|
||||
return userName;
|
||||
}
|
||||
|
||||
private String fetchServiceTicket(final String ticketGrantingTicket) {
|
||||
final var tgtUrl = casServerUrl + "/cas/v1/tickets/" + ticketGrantingTicket;
|
||||
|
||||
final var restTemplate = new RestTemplate();
|
||||
final var formData = new LinkedMultiValueMap<String, String>();
|
||||
formData.add("service", serviceUrl);
|
||||
|
||||
return restTemplate.postForObject(tgtUrl, formData, String.class);
|
||||
}
|
||||
|
||||
private Document verifyServiceTicket(final String serviceTicket) throws SAXException, IOException, ParserConfigurationException {
|
||||
if ( !serviceTicket.startsWith("ST-") ) {
|
||||
throwBadCredentialsException("auth.unknown-authorization-ticket");
|
||||
}
|
||||
|
||||
final var url = casServerUrl + "/cas/p3/serviceValidate" +
|
||||
"?service=" + serviceUrl +
|
||||
"&ticket=" + serviceTicket;
|
||||
|
||||
final var response = restTemplate.getForObject(url, String.class);
|
||||
|
||||
return DocumentBuilderFactory.newInstance().newDocumentBuilder()
|
||||
.parse(new java.io.ByteArrayInputStream(response.getBytes()));
|
||||
|
||||
}
|
||||
|
||||
private String extractUserName(final Document verification) {
|
||||
|
||||
if (verification.getElementsByTagName("cas:authenticationSuccess").getLength() == 0) {
|
||||
throwBadCredentialsException("auth.cas-service-ticket-could-not-be-verified");
|
||||
}
|
||||
return verification.getElementsByTagName("cas:user").item(0).getTextContent();
|
||||
}
|
||||
|
||||
private void throwBadCredentialsException(final String messageKey) {
|
||||
final var translatedMessage = messageTranslator.translate(messageKey);
|
||||
throw new BadCredentialsException(translatedMessage);
|
||||
}
|
||||
}
|
||||
@@ -1,77 +1,12 @@
|
||||
package net.hostsharing.hsadminng.config;
|
||||
|
||||
import io.swagger.v3.oas.annotations.enums.SecuritySchemeIn;
|
||||
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityScheme;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.authentication.AuthenticationFilter;
|
||||
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableMethodSecurity(prePostEnabled = true) // Add this annotation
|
||||
// TODO.impl: securitySchemes should work in OpenAPI yaml, but the Spring templates seem not to support it
|
||||
@SecurityScheme(type = SecuritySchemeType.HTTP, name = "casTicket", scheme = "bearer", bearerFormat = "CAS ticket", description = "CAS ticket", in = SecuritySchemeIn.HEADER)
|
||||
public class WebSecurityConfig {
|
||||
|
||||
@Lazy
|
||||
@Autowired
|
||||
private CasAuthenticationFilter authenticationFilter;
|
||||
|
||||
@Autowired
|
||||
private MessageTranslator messageTranslator;
|
||||
|
||||
@Bean
|
||||
@Profile("!test")
|
||||
public SecurityFilterChain securityFilterChain(final HttpSecurity http) throws Exception {
|
||||
return http
|
||||
.authorizeHttpRequests(authorize -> authorize
|
||||
.requestMatchers(
|
||||
// only list endpoints implemented in libraries here
|
||||
"/swagger-ui/**",
|
||||
"/v3/api-docs/**",
|
||||
"/actuator/**"
|
||||
// otherwise use @PreAuthorize annotation at the controller class / endpoint method level
|
||||
).permitAll()
|
||||
.requestMatchers("/api/**").permitAll() // controlled at method level
|
||||
.anyRequest().denyAll()
|
||||
)
|
||||
.addFilterBefore(authenticationFilter, AuthenticationFilter.class)
|
||||
.csrf(AbstractHttpConfigurer::disable)
|
||||
.exceptionHandling(exception -> exception
|
||||
.authenticationEntryPoint((request, response, authException) ->
|
||||
// For unknown reasons Spring security returns 403 FORBIDDEN for a BadCredentialsException.
|
||||
// But it should return 401 UNAUTHORIZED.
|
||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED)
|
||||
)
|
||||
)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Profile("realCasAuthenticator")
|
||||
public CasAuthenticator realCasServiceTicketValidator() {
|
||||
return new RealCasAuthenticator(messageTranslator);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Profile("fakeCasAuthenticator")
|
||||
public CasAuthenticator fakeCasServiceTicketValidator() {
|
||||
return new FakeCasAuthenticator();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CasAuthenticationFilter authenticationFilter(final CasAuthenticator authenticator) {
|
||||
return new CasAuthenticationFilter(authenticator);
|
||||
}
|
||||
@Profile("!test")
|
||||
@EnableMethodSecurity // this does not work with @WebMvcTest, see WebSecurityConfigForWebMvcTests
|
||||
public class WebSecurityConfig extends BaseWebSecurityConfig {
|
||||
}
|
||||
|
||||
+1
-4
@@ -5,19 +5,17 @@ import java.util.List;
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import lombok.val;
|
||||
import net.hostsharing.hsadminng.config.NoSecurityRequirement;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.rbac.context.Context;
|
||||
import net.hostsharing.hsadminng.accounts.generated.api.v1.api.ContextsApi;
|
||||
import net.hostsharing.hsadminng.accounts.generated.api.v1.model.ContextResource;
|
||||
import net.hostsharing.hsadminng.mapper.StrictMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@NoSecurityRequirement
|
||||
public class HsCredentialsContextsController implements ContextsApi {
|
||||
|
||||
@@ -33,7 +31,6 @@ public class HsCredentialsContextsController implements ContextsApi {
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
@Timed("app.credentials.contexts.getListOfLoginContexts")
|
||||
@PreAuthorize("permitAll()")
|
||||
public ResponseEntity<List<ContextResource>> getListOfContexts(final String assumedRoles) {
|
||||
if (SecurityContextHolder.getContext().getAuthentication().isAuthenticated()) {
|
||||
context.assumeRoles(assumedRoles);
|
||||
|
||||
@@ -14,7 +14,7 @@ import net.hostsharing.hsadminng.accounts.generated.api.v1.model.ContextResource
|
||||
import net.hostsharing.hsadminng.accounts.generated.api.v1.model.CurrentLoginUserResource;
|
||||
import net.hostsharing.hsadminng.accounts.generated.api.v1.model.RbacSubjectResource;
|
||||
import net.hostsharing.hsadminng.config.MessageTranslator;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.rbac.context.Context;
|
||||
import net.hostsharing.hsadminng.accounts.generated.api.v1.api.CredentialsApi;
|
||||
import net.hostsharing.hsadminng.accounts.generated.api.v1.model.CredentialsInsertResource;
|
||||
import net.hostsharing.hsadminng.accounts.generated.api.v1.model.CredentialsPatchResource;
|
||||
@@ -42,7 +42,7 @@ import static java.util.Optional.of;
|
||||
|
||||
@RestController
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
@SecurityRequirement(name = "bearerAuth")
|
||||
public class HsCredentialsController implements CredentialsApi {
|
||||
|
||||
@Autowired
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.rbac.context.Context;
|
||||
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.api.HsBookingItemsApi;
|
||||
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsBookingItemInsertResource;
|
||||
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsBookingItemPatchResource;
|
||||
@@ -35,7 +35,7 @@ import static net.hostsharing.hsadminng.mapper.PostgresDateRange.toPostgresDateR
|
||||
@RestController
|
||||
@Profile("!only-prod-schema")
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
@SecurityRequirement(name = "bearerAuth")
|
||||
public class HsBookingItemController implements HsBookingItemsApi {
|
||||
|
||||
@Autowired
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ package net.hostsharing.hsadminng.hs.booking.project;
|
||||
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.rbac.context.Context;
|
||||
import net.hostsharing.hsadminng.hs.booking.debitor.HsBookingDebitorRepository;
|
||||
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.api.HsBookingProjectsApi;
|
||||
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsBookingProjectInsertResource;
|
||||
@@ -25,7 +25,7 @@ import java.util.function.BiConsumer;
|
||||
@RestController
|
||||
@Profile("!only-prod-schema")
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
@SecurityRequirement(name = "bearerAuth")
|
||||
public class HsBookingProjectController implements HsBookingProjectsApi {
|
||||
|
||||
@Autowired
|
||||
|
||||
+2
-2
@@ -7,7 +7,7 @@ import net.hostsharing.hsadminng.hs.hosting.asset.validators.HostingAssetEntityS
|
||||
import net.hostsharing.hsadminng.hs.hosting.asset.validators.HostingAssetEntityValidatorRegistry;
|
||||
import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.api.HsHostingAssetsApi;
|
||||
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.rbac.context.Context;
|
||||
import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.model.HsHostingAssetInsertResource;
|
||||
import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.model.HsHostingAssetPatchResource;
|
||||
import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.model.HsHostingAssetResource;
|
||||
@@ -32,7 +32,7 @@ import java.util.function.BiConsumer;
|
||||
@RestController
|
||||
@Profile("!only-prod-schema")
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
@SecurityRequirement(name = "bearerAuth")
|
||||
public class HsHostingAssetController implements HsHostingAssetsApi {
|
||||
|
||||
@Autowired
|
||||
|
||||
-4
@@ -7,7 +7,6 @@ import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.api.HsHostingAssetP
|
||||
import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.model.HsHostingAssetTypeResource;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
@@ -16,12 +15,10 @@ import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@Profile("!only-prod-schema")
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@NoSecurityRequirement
|
||||
public class HsHostingAssetPropsController implements HsHostingAssetPropsApi {
|
||||
|
||||
@Override
|
||||
@PreAuthorize("permitAll()")
|
||||
@Timed("app.hosting.assets.api.getListOfHostingAssetTypes")
|
||||
public ResponseEntity<List<String>> getListOfHostingAssetTypes() {
|
||||
final var resource = HostingAssetEntityValidatorRegistry.types().stream()
|
||||
@@ -31,7 +28,6 @@ public class HsHostingAssetPropsController implements HsHostingAssetPropsApi {
|
||||
}
|
||||
|
||||
@Override
|
||||
@PreAuthorize("permitAll()")
|
||||
@Timed("app.hosting.assets.api.getListOfHostingAssetTypeProps")
|
||||
public ResponseEntity<List<Object>> getListOfHostingAssetTypeProps(
|
||||
final HsHostingAssetTypeResource assetType) {
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ package net.hostsharing.hsadminng.hs.office.bankaccount;
|
||||
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.rbac.context.Context;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeBankAccountsApi;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeBankAccountInsertResource;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeBankAccountResource;
|
||||
@@ -21,7 +21,7 @@ import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
@SecurityRequirement(name = "bearerAuth")
|
||||
public class HsOfficeBankAccountController implements HsOfficeBankAccountsApi {
|
||||
|
||||
@Autowired
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ package net.hostsharing.hsadminng.hs.office.contact;
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import net.hostsharing.hsadminng.mapper.StrictMapper;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.rbac.context.Context;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeContactsApi;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeContactInsertResource;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeContactPatchResource;
|
||||
@@ -23,7 +23,7 @@ import static net.hostsharing.hsadminng.errors.Validate.validate;
|
||||
|
||||
@RestController
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
@SecurityRequirement(name = "bearerAuth")
|
||||
public class HsOfficeContactController implements HsOfficeContactsApi {
|
||||
|
||||
@Autowired
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ package net.hostsharing.hsadminng.hs.office.coopassets;
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import net.hostsharing.hsadminng.config.MessageTranslator;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.rbac.context.Context;
|
||||
import net.hostsharing.hsadminng.errors.MultiValidationException;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeCoopAssetsApi;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeCoopAssetsTransactionInsertResource;
|
||||
@@ -40,7 +40,7 @@ import static net.hostsharing.hsadminng.lambda.WithNonNull.withNonNull;
|
||||
|
||||
@RestController
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
@SecurityRequirement(name = "bearerAuth")
|
||||
public class HsOfficeCoopAssetsTransactionController implements HsOfficeCoopAssetsApi {
|
||||
|
||||
@Autowired
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ package net.hostsharing.hsadminng.hs.office.coopshares;
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import net.hostsharing.hsadminng.config.MessageTranslator;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.rbac.context.Context;
|
||||
import net.hostsharing.hsadminng.errors.MultiValidationException;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeCoopSharesApi;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeCoopSharesTransactionInsertResource;
|
||||
@@ -31,7 +31,7 @@ import static net.hostsharing.hsadminng.hs.validation.UuidResolver.resolve;
|
||||
|
||||
@RestController
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
@SecurityRequirement(name = "bearerAuth")
|
||||
public class HsOfficeCoopSharesTransactionController implements HsOfficeCoopSharesApi {
|
||||
|
||||
@Autowired
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ package net.hostsharing.hsadminng.hs.office.debitor;
|
||||
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.rbac.context.Context;
|
||||
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository;
|
||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealRepository;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeDebitorsApi;
|
||||
@@ -35,7 +35,7 @@ import static net.hostsharing.hsadminng.repr.TaggedNumber.cropTag;
|
||||
|
||||
@RestController
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
@SecurityRequirement(name = "bearerAuth")
|
||||
public class HsOfficeDebitorController implements HsOfficeDebitorsApi {
|
||||
|
||||
@Autowired
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ package net.hostsharing.hsadminng.hs.office.membership;
|
||||
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.rbac.context.Context;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeMembershipsApi;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeMembershipInsertResource;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeMembershipPatchResource;
|
||||
@@ -27,7 +27,7 @@ import static net.hostsharing.hsadminng.repr.TaggedNumber.cropTag;
|
||||
|
||||
@RestController
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
@SecurityRequirement(name = "bearerAuth")
|
||||
public class HsOfficeMembershipController implements HsOfficeMembershipsApi {
|
||||
|
||||
@Autowired
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ package net.hostsharing.hsadminng.hs.office.partner;
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import net.hostsharing.hsadminng.config.MessageTranslator;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.rbac.context.Context;
|
||||
import net.hostsharing.hsadminng.errors.ReferenceNotFoundException;
|
||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactFromResourceConverter;
|
||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity;
|
||||
@@ -39,7 +39,7 @@ import static net.hostsharing.hsadminng.repr.TaggedNumber.cropTag;
|
||||
|
||||
@RestController
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
@SecurityRequirement(name = "bearerAuth")
|
||||
public class HsOfficePartnerController implements HsOfficePartnersApi {
|
||||
|
||||
@Autowired
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ package net.hostsharing.hsadminng.hs.office.person;
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import net.hostsharing.hsadminng.mapper.StrictMapper;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.rbac.context.Context;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficePersonsApi;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficePersonInsertResource;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficePersonPatchResource;
|
||||
@@ -20,7 +20,7 @@ import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
@SecurityRequirement(name = "bearerAuth")
|
||||
public class HsOfficePersonController implements HsOfficePersonsApi {
|
||||
|
||||
@Autowired
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ package net.hostsharing.hsadminng.hs.office.relation;
|
||||
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.rbac.context.Context;
|
||||
import net.hostsharing.hsadminng.errors.Validate;
|
||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity;
|
||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealRepository;
|
||||
@@ -29,7 +29,7 @@ import static net.hostsharing.hsadminng.mapper.KeyValueMap.from;
|
||||
|
||||
@RestController
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
@SecurityRequirement(name = "bearerAuth")
|
||||
public class HsOfficeRelationController implements HsOfficeRelationsApi {
|
||||
|
||||
@Autowired
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ package net.hostsharing.hsadminng.hs.office.sepamandate;
|
||||
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.rbac.context.Context;
|
||||
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository;
|
||||
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeSepaMandatesApi;
|
||||
@@ -27,7 +27,7 @@ import static net.hostsharing.hsadminng.mapper.PostgresDateRange.toPostgresDateR
|
||||
|
||||
@RestController
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
@SecurityRequirement(name = "bearerAuth")
|
||||
public class HsOfficeSepaMandateController implements HsOfficeSepaMandatesApi {
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -6,19 +6,16 @@ import net.hostsharing.hsadminng.config.NoSecurityRequirement;
|
||||
import net.hostsharing.hsadminng.generated.api.v1.api.TestApi;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@NoSecurityRequirement
|
||||
public class PingController implements TestApi {
|
||||
|
||||
@Autowired
|
||||
private MessageTranslator messageTranslator;
|
||||
|
||||
@PreAuthorize("permitAll()")
|
||||
@Timed("app.api.ping")
|
||||
public ResponseEntity<String> ping() {
|
||||
// HOWTO translate text with placeholders - also see in resource files i18n/messages_*.properties.
|
||||
@@ -26,7 +23,6 @@ public class PingController implements TestApi {
|
||||
return ResponseEntity.ok(translatedMessage + "\n");
|
||||
}
|
||||
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@Timed("app.api.pong")
|
||||
public ResponseEntity<String> pong() {
|
||||
final var userName = SecurityContextHolder.getContext().getAuthentication().getName();
|
||||
|
||||
+25
-2
@@ -1,7 +1,8 @@
|
||||
package net.hostsharing.hsadminng.context;
|
||||
package net.hostsharing.hsadminng.rbac.context;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.val;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
@@ -9,6 +10,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
|
||||
import jakarta.persistence.EntityExistsException;
|
||||
import jakarta.persistence.EntityManager;
|
||||
import jakarta.persistence.PersistenceContext;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
@@ -74,7 +76,7 @@ public class Context {
|
||||
""");
|
||||
query.setParameter("currentTask", shortenToMaxLength(currentTask, 127));
|
||||
query.setParameter("currentRequest", currentRequest);
|
||||
query.setParameter("currentSubject", currentSubject);
|
||||
query.setParameter("currentSubject", subjectName(currentSubject));
|
||||
query.setParameter("assumedRoles", assumedRoles != null ? assumedRoles : "");
|
||||
query.executeUpdate();
|
||||
}
|
||||
@@ -119,6 +121,27 @@ public class Context {
|
||||
.orElse("unknown");
|
||||
}
|
||||
|
||||
private String subjectName(final String nameOrUuid) {
|
||||
if (nameOrUuid == null) {
|
||||
return null;
|
||||
}
|
||||
// TODO.impl: maybe it should be the other way around: UUID as the default and just optionally the name
|
||||
try {
|
||||
val authenticatedUuid = UUID.fromString(nameOrUuid);
|
||||
val subjectName = findSubjectNameByUuid(authenticatedUuid)
|
||||
.orElseThrow(() -> new EntityExistsException("Subject not found"));
|
||||
return subjectName;
|
||||
} catch (final IllegalArgumentException e) {
|
||||
return nameOrUuid;
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<String> findSubjectNameByUuid(final UUID authenticatedUuid) {
|
||||
return Optional.ofNullable(em.createNativeQuery("SELECT name FROM rbac.subject s WHERE s.uuid=:uuid")
|
||||
.setParameter("uuid", authenticatedUuid)
|
||||
.getSingleResult()).map(Object::toString);
|
||||
}
|
||||
|
||||
private String toTask(final HttpServletRequest request) {
|
||||
if (isRequestScopeAvailable()) {
|
||||
return request.getMethod() + " " + request.getRequestURI();
|
||||
@@ -2,7 +2,6 @@ package net.hostsharing.hsadminng.rbac.context;
|
||||
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.mapper.StrictMapper;
|
||||
import net.hostsharing.hsadminng.rbac.generated.api.v1.api.RbacContextApi;
|
||||
import net.hostsharing.hsadminng.rbac.generated.api.v1.model.RbacContextResource;
|
||||
@@ -23,7 +22,7 @@ import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
@SecurityRequirement(name = "bearerAuth")
|
||||
public class RbacContextController implements RbacContextApi {
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -2,7 +2,7 @@ package net.hostsharing.hsadminng.rbac.grant;
|
||||
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.rbac.context.Context;
|
||||
import net.hostsharing.hsadminng.mapper.StrictMapper;
|
||||
import net.hostsharing.hsadminng.rbac.generated.api.v1.api.RbacGrantsApi;
|
||||
import net.hostsharing.hsadminng.rbac.generated.api.v1.model.RbacGrantResource;
|
||||
@@ -20,7 +20,7 @@ import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
@SecurityRequirement(name = "bearerAuth")
|
||||
public class RbacGrantController implements RbacGrantsApi {
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package net.hostsharing.hsadminng.rbac.grant;
|
||||
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.rbac.context.Context;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package net.hostsharing.hsadminng.rbac.role;
|
||||
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.rbac.context.Context;
|
||||
import net.hostsharing.hsadminng.mapper.StrictMapper;
|
||||
import net.hostsharing.hsadminng.rbac.generated.api.v1.api.RbacRolesApi;
|
||||
import net.hostsharing.hsadminng.rbac.generated.api.v1.model.RbacRoleResource;
|
||||
@@ -16,7 +16,7 @@ import java.util.List;
|
||||
|
||||
@RestController
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
@SecurityRequirement(name = "bearerAuth")
|
||||
public class RbacRoleController implements RbacRolesApi {
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -2,7 +2,7 @@ package net.hostsharing.hsadminng.rbac.subject;
|
||||
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.rbac.context.Context;
|
||||
import net.hostsharing.hsadminng.mapper.StrictMapper;
|
||||
import net.hostsharing.hsadminng.rbac.generated.api.v1.api.RbacSubjectsApi;
|
||||
import net.hostsharing.hsadminng.rbac.generated.api.v1.model.RbacSubjectPermissionResource;
|
||||
@@ -19,7 +19,7 @@ import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
@SecurityRequirement(name = "bearerAuth")
|
||||
public class RbacSubjectController implements RbacSubjectsApi {
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package net.hostsharing.hsadminng.rbac.test.cust;
|
||||
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.rbac.context.Context;
|
||||
import net.hostsharing.hsadminng.mapper.StrictMapper;
|
||||
import net.hostsharing.hsadminng.test.generated.api.v1.api.TestCustomersApi;
|
||||
import net.hostsharing.hsadminng.test.generated.api.v1.model.TestCustomerResource;
|
||||
@@ -18,7 +18,7 @@ import java.util.List;
|
||||
|
||||
@RestController
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
@SecurityRequirement(name = "bearerAuth")
|
||||
public class TestCustomerController implements TestCustomersApi {
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -3,7 +3,7 @@ package net.hostsharing.hsadminng.rbac.test.pac;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import net.hostsharing.hsadminng.mapper.StrictMapper;
|
||||
import net.hostsharing.hsadminng.mapper.OptionalFromJson;
|
||||
import net.hostsharing.hsadminng.context.Context;
|
||||
import net.hostsharing.hsadminng.rbac.context.Context;
|
||||
import net.hostsharing.hsadminng.test.generated.api.v1.api.TestPackagesApi;
|
||||
import net.hostsharing.hsadminng.test.generated.api.v1.model.TestPackageResource;
|
||||
import net.hostsharing.hsadminng.test.generated.api.v1.model.TestPackageUpdateResource;
|
||||
@@ -18,7 +18,7 @@ import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@PreAuthorize("isAuthenticated()")
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
@SecurityRequirement(name = "bearerAuth")
|
||||
public class TestPackageController implements TestPackagesApi {
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -147,15 +147,11 @@ public final class Stringify<B> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
PropertyValue(final B object, final Property<B, ?> prop) {
|
||||
// FIXME: simplify
|
||||
final var typedProp = (Property<B, V>) prop;
|
||||
final var value = typedProp.getValue(object);
|
||||
final var stringifiedValue = value instanceof Stringifyable stringifyable
|
||||
? stringifyable.toShortString()
|
||||
: Objects.toString(value);
|
||||
this.prop = typedProp;
|
||||
this.value = (V) value;
|
||||
this.stringValue = stringifiedValue;
|
||||
this.prop = (Property<B, V>) prop;
|
||||
this.value = (V) this.prop.getValue(object);
|
||||
this.stringValue = this.value instanceof Stringifyable s
|
||||
? s.toShortString()
|
||||
: Objects.toString(this.value);
|
||||
}
|
||||
|
||||
boolean notNullAndNotEmpty() {
|
||||
|
||||
@@ -54,12 +54,16 @@ spring:
|
||||
liquibase:
|
||||
contexts: ${spring.profiles.active}
|
||||
|
||||
security:
|
||||
oauth2:
|
||||
resourceserver:
|
||||
jwt:
|
||||
issuer-uri: ${HSADMINNG_JWT_ISSUER:}
|
||||
jwk-set-uri: ${HSADMINNG_JWT_JWKS_URL:}
|
||||
|
||||
hsadminng:
|
||||
postgres:
|
||||
leakproof:
|
||||
cas:
|
||||
server: https://login.hostsharing.net/cas # use empty string to bypass CAS-validation and directly use current-subject
|
||||
service: https://hsadminng.hostsharing.net:443 # TODO.conf: deployment target + matching CAS service ID
|
||||
|
||||
metrics:
|
||||
distribution:
|
||||
@@ -78,3 +82,17 @@ logging:
|
||||
# HOWTO configure logging, e.g. logging to a separate file, see:
|
||||
# https://docs.spring.io/spring-boot/reference/features/logging.html
|
||||
|
||||
---
|
||||
|
||||
spring:
|
||||
config:
|
||||
activate:
|
||||
on-profile: fake-jwt
|
||||
security:
|
||||
oauth2:
|
||||
resourceserver:
|
||||
jwt:
|
||||
issuer-uri: "http://localhost:${server.port}/fake-jwt"
|
||||
jwk-set-uri: "http://localhost:${server.port}/fake-jwt/.well-known/jwks.json"
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user