unauthenticated swagger-ui on- server-port and proper security filter integration into Spring Security (#163)
Co-authored-by: Michael Hoennig <michael@hoennig.de> Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/163 Reviewed-by: Marc Sandlus <marc.sandlus@hostsharing.net>
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
package net.hostsharing.hsadminng;
|
||||
|
||||
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
@OpenAPIDefinition
|
||||
public class HsadminNgApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
@@ -1,39 +0,0 @@
|
||||
package net.hostsharing.hsadminng.config;
|
||||
|
||||
import jakarta.servlet.Filter;
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.ServletRequest;
|
||||
import jakarta.servlet.ServletResponse;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class AuthenticationFilter implements Filter {
|
||||
|
||||
@Autowired
|
||||
private Authenticator authenticator;
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) {
|
||||
final var httpRequest = (HttpServletRequest) request;
|
||||
final var httpResponse = (HttpServletResponse) response;
|
||||
|
||||
try {
|
||||
final var currentSubject = authenticator.authenticate(httpRequest);
|
||||
|
||||
final var authenticatedRequest = new AuthenticatedHttpServletRequestWrapper(httpRequest);
|
||||
authenticatedRequest.addHeader("current-subject", currentSubject);
|
||||
|
||||
chain.doFilter(authenticatedRequest, response);
|
||||
} catch (final BadCredentialsException exc) {
|
||||
// TODO.impl: should not be necessary if ResponseStatusException worked
|
||||
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
package net.hostsharing.hsadminng.config;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
public interface Authenticator {
|
||||
|
||||
String authenticate(final HttpServletRequest httpRequest);
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
package net.hostsharing.hsadminng.config;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
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);
|
||||
authenticatedRequest.addHeader("current-subject", currentSubject);
|
||||
filterChain.doFilter(authenticatedRequest, response);
|
||||
} else {
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,71 +1,8 @@
|
||||
package net.hostsharing.hsadminng.config;
|
||||
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import lombok.SneakyThrows;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import java.io.IOException;
|
||||
|
||||
public class CasAuthenticator implements Authenticator {
|
||||
public interface CasAuthenticator {
|
||||
|
||||
@Value("${hsadminng.cas.server}")
|
||||
private String casServerUrl;
|
||||
|
||||
@Value("${hsadminng.cas.service}")
|
||||
private String serviceUrl;
|
||||
|
||||
private final RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
@SneakyThrows
|
||||
@Timed("app.cas.authenticate")
|
||||
public String authenticate(final HttpServletRequest httpRequest) {
|
||||
final var userName = StringUtils.isBlank(casServerUrl)
|
||||
? bypassCurrentSubject(httpRequest)
|
||||
: casValidation(httpRequest);
|
||||
final var authentication = new UsernamePasswordAuthenticationToken(userName, null, null);
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
return authentication.getName();
|
||||
}
|
||||
|
||||
private static String bypassCurrentSubject(final HttpServletRequest httpRequest) {
|
||||
final var userName = httpRequest.getHeader("current-subject");
|
||||
System.err.println("CasAuthenticator.bypassCurrentSubject: " + userName);
|
||||
return userName;
|
||||
}
|
||||
|
||||
private String casValidation(final HttpServletRequest httpRequest)
|
||||
throws SAXException, IOException, ParserConfigurationException {
|
||||
|
||||
final var ticket = httpRequest.getHeader("Authorization");
|
||||
final var url = casServerUrl + "/p3/serviceValidate" +
|
||||
"?service=" + serviceUrl +
|
||||
"&ticket=" + ticket;
|
||||
|
||||
System.err.println("CasAuthenticator.casValidation using URL: " + url);
|
||||
|
||||
final var response = restTemplate.getForObject(url, String.class);
|
||||
|
||||
final var doc = DocumentBuilderFactory.newInstance().newDocumentBuilder()
|
||||
.parse(new java.io.ByteArrayInputStream(response.getBytes()));
|
||||
if (doc.getElementsByTagName("cas:authenticationSuccess").getLength() == 0) {
|
||||
// TODO.impl: for unknown reasons, this results in a 403 FORBIDDEN
|
||||
// throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "CAS service ticket could not be validated");
|
||||
System.err.println("CAS service ticket could not be validated");
|
||||
System.err.println("CAS-validation-URL: " + url);
|
||||
System.err.println(response);
|
||||
throw new BadCredentialsException("CAS service ticket could not be validated");
|
||||
}
|
||||
final var userName = doc.getElementsByTagName("cas:user").item(0).getTextContent();
|
||||
System.err.println("CAS-user: " + userName);
|
||||
return userName;
|
||||
}
|
||||
String authenticate(final HttpServletRequest httpRequest);
|
||||
}
|
||||
|
@@ -0,0 +1,18 @@
|
||||
package net.hostsharing.hsadminng.config;
|
||||
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
|
||||
/** Explicitly marks a REST-Controller for not requiring authorization for Swagger UI.
|
||||
*
|
||||
* @see SecurityRequirement
|
||||
*/
|
||||
@Target(TYPE)
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
public @interface NoSecurityRequirement {
|
||||
}
|
@@ -0,0 +1,100 @@
|
||||
package net.hostsharing.hsadminng.config;
|
||||
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import lombok.SneakyThrows;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
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;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class RealCasAuthenticator implements CasAuthenticator {
|
||||
|
||||
@Value("${hsadminng.cas.server}")
|
||||
private String casServerUrl;
|
||||
|
||||
@Value("${hsadminng.cas.service}")
|
||||
private String serviceUrl;
|
||||
|
||||
private final RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
@SneakyThrows
|
||||
@Timed("app.cas.authenticate")
|
||||
public String authenticate(final HttpServletRequest httpRequest) {
|
||||
final var userName = StringUtils.isBlank(casServerUrl)
|
||||
? bypassCurrentSubject(httpRequest)
|
||||
: casAuthentication(httpRequest);
|
||||
final var authentication = new UsernamePasswordAuthenticationToken(userName, null, null);
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
return authentication.getName();
|
||||
}
|
||||
|
||||
private static String bypassCurrentSubject(final HttpServletRequest httpRequest) {
|
||||
final var userName = httpRequest.getHeader("authorization").replaceAll("^Bearer ", "");
|
||||
System.err.println("CasAuthenticator.bypassCurrentSubject: " + userName);
|
||||
return userName;
|
||||
}
|
||||
|
||||
private String casAuthentication(final HttpServletRequest httpRequest)
|
||||
throws SAXException, IOException, ParserConfigurationException {
|
||||
|
||||
final var ticket = httpRequest.getHeader("authorization").replaceAll("^Bearer ", "");
|
||||
final var serviceTicket = ticket.startsWith("TGT-")
|
||||
? fetchServiceTicket(ticket)
|
||||
: ticket;
|
||||
final var userName = extractUserName(verifyServiceTicket(serviceTicket));
|
||||
System.err.println("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("Invalid authorization ticket");
|
||||
}
|
||||
|
||||
final var url = casServerUrl + "/cas/p3/serviceValidate" +
|
||||
"?service=" + serviceUrl +
|
||||
"&ticket=" + serviceTicket;
|
||||
|
||||
final var response = ((Supplier<String>) () -> restTemplate.getForObject(url, String.class)).get();
|
||||
|
||||
return DocumentBuilderFactory.newInstance().newDocumentBuilder()
|
||||
.parse(new java.io.ByteArrayInputStream(response.getBytes()));
|
||||
|
||||
}
|
||||
|
||||
private String extractUserName(final Document verification) {
|
||||
|
||||
if (verification.getElementsByTagName("cas:authenticationSuccess").getLength() == 0) {
|
||||
System.err.println("CAS service ticket could not be validated");
|
||||
System.err.println(verification);
|
||||
throwBadCredentialsException("CAS service ticket could not be validated");
|
||||
}
|
||||
return verification.getElementsByTagName("cas:user").item(0).getTextContent();
|
||||
}
|
||||
|
||||
private String throwBadCredentialsException(final String message) {
|
||||
throw new BadCredentialsException(message);
|
||||
}
|
||||
|
||||
}
|
@@ -1,36 +1,63 @@
|
||||
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.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
|
||||
// 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 {
|
||||
|
||||
private static final String[] PERMITTED_PATHS = new String[] { "/swagger-ui/**", "/v3/api-docs/**", "/actuator/**" };
|
||||
private static final String[] AUTHENTICATED_PATHS = new String[] { "/api/**" };
|
||||
|
||||
@Lazy
|
||||
@Autowired
|
||||
private CasAuthenticationFilter authenticationFilter;
|
||||
|
||||
@Bean
|
||||
@Profile("!test")
|
||||
public SecurityFilterChain securityFilterChain(final HttpSecurity http) throws Exception {
|
||||
return http
|
||||
.authorizeHttpRequests(authorize -> authorize
|
||||
.requestMatchers("/api/**").permitAll() // TODO.impl: implement authentication
|
||||
.requestMatchers("/swagger-ui/**").permitAll()
|
||||
.requestMatchers("/v3/api-docs/**").permitAll()
|
||||
.requestMatchers("/actuator/**").permitAll()
|
||||
.anyRequest().authenticated()
|
||||
.requestMatchers(PERMITTED_PATHS).permitAll()
|
||||
.requestMatchers(AUTHENTICATED_PATHS).authenticated()
|
||||
.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("!test")
|
||||
public Authenticator casServiceTicketValidator() {
|
||||
return new CasAuthenticator();
|
||||
public CasAuthenticator casServiceTicketValidator() {
|
||||
return new RealCasAuthenticator();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CasAuthenticationFilter authenticationFilter(final CasAuthenticator authenticator) {
|
||||
return new CasAuthenticationFilter(authenticator);
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package net.hostsharing.hsadminng.hs.booking.item;
|
||||
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.hs.booking.generated.api.v1.api.HsBookingItemsApi;
|
||||
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsBookingItemInsertResource;
|
||||
@@ -32,6 +33,7 @@ import static net.hostsharing.hsadminng.mapper.PostgresDateRange.toPostgresDateR
|
||||
|
||||
@RestController
|
||||
@Profile("!only-office")
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
public class HsBookingItemController implements HsBookingItemsApi {
|
||||
|
||||
@Autowired
|
||||
|
@@ -1,6 +1,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.hs.booking.debitor.HsBookingDebitorRepository;
|
||||
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.api.HsBookingProjectsApi;
|
||||
@@ -22,6 +23,7 @@ import java.util.function.BiConsumer;
|
||||
|
||||
@RestController
|
||||
@Profile("!only-office")
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
public class HsBookingProjectController implements HsBookingProjectsApi {
|
||||
|
||||
@Autowired
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package net.hostsharing.hsadminng.hs.hosting.asset;
|
||||
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRealRepository;
|
||||
import net.hostsharing.hsadminng.hs.hosting.asset.validators.HostingAssetEntitySaveProcessor;
|
||||
import net.hostsharing.hsadminng.hs.hosting.asset.validators.HostingAssetEntityValidatorRegistry;
|
||||
@@ -29,6 +30,7 @@ import java.util.function.BiConsumer;
|
||||
|
||||
@RestController
|
||||
@Profile("!only-office")
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
public class HsHostingAssetController implements HsHostingAssetsApi {
|
||||
|
||||
@Autowired
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package net.hostsharing.hsadminng.hs.hosting.asset;
|
||||
|
||||
import io.micrometer.core.annotation.Timed;
|
||||
import net.hostsharing.hsadminng.config.NoSecurityRequirement;
|
||||
import net.hostsharing.hsadminng.hs.hosting.asset.validators.HostingAssetEntityValidatorRegistry;
|
||||
import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.api.HsHostingAssetPropsApi;
|
||||
import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.model.HsHostingAssetTypeResource;
|
||||
@@ -14,6 +15,7 @@ import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@Profile("!only-office")
|
||||
@NoSecurityRequirement
|
||||
public class HsHostingAssetPropsController implements HsHostingAssetPropsApi {
|
||||
|
||||
@Override
|
||||
|
@@ -1,6 +1,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.hs.office.generated.api.v1.api.HsOfficeBankAccountsApi;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeBankAccountInsertResource;
|
||||
@@ -18,7 +19,7 @@ import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
public class HsOfficeBankAccountController implements HsOfficeBankAccountsApi {
|
||||
|
||||
@Autowired
|
||||
|
@@ -1,6 +1,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.hs.office.generated.api.v1.api.HsOfficeContactsApi;
|
||||
@@ -20,6 +21,7 @@ import java.util.UUID;
|
||||
import static net.hostsharing.hsadminng.errors.Validate.validate;
|
||||
|
||||
@RestController
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
public class HsOfficeContactController implements HsOfficeContactsApi {
|
||||
|
||||
@Autowired
|
||||
|
@@ -1,6 +1,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.context.Context;
|
||||
import net.hostsharing.hsadminng.errors.MultiValidationException;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeCoopAssetsApi;
|
||||
@@ -37,6 +38,7 @@ import static net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOffic
|
||||
import static net.hostsharing.hsadminng.lambda.WithNonNull.withNonNull;
|
||||
|
||||
@RestController
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
public class HsOfficeCoopAssetsTransactionController implements HsOfficeCoopAssetsApi {
|
||||
|
||||
@Autowired
|
||||
|
@@ -1,6 +1,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.context.Context;
|
||||
import net.hostsharing.hsadminng.errors.MultiValidationException;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeCoopSharesApi;
|
||||
@@ -27,6 +28,7 @@ import static net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOffic
|
||||
import static net.hostsharing.hsadminng.hs.validation.UuidResolver.resolve;
|
||||
|
||||
@RestController
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
public class HsOfficeCoopSharesTransactionController implements HsOfficeCoopSharesApi {
|
||||
|
||||
@Autowired
|
||||
|
@@ -1,6 +1,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.hs.office.bankaccount.HsOfficeBankAccountRepository;
|
||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealRepository;
|
||||
@@ -32,7 +33,7 @@ import static net.hostsharing.hsadminng.hs.validation.UuidResolver.resolve;
|
||||
import static net.hostsharing.hsadminng.repr.TaggedNumber.cropTag;
|
||||
|
||||
@RestController
|
||||
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
public class HsOfficeDebitorController implements HsOfficeDebitorsApi {
|
||||
|
||||
@Autowired
|
||||
|
@@ -1,6 +1,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.hs.office.generated.api.v1.api.HsOfficeMembershipsApi;
|
||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeMembershipInsertResource;
|
||||
@@ -24,6 +25,7 @@ import static net.hostsharing.hsadminng.errors.Validate.validate;
|
||||
import static net.hostsharing.hsadminng.repr.TaggedNumber.cropTag;
|
||||
|
||||
@RestController
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
public class HsOfficeMembershipController implements HsOfficeMembershipsApi {
|
||||
|
||||
@Autowired
|
||||
|
@@ -1,6 +1,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.context.Context;
|
||||
import net.hostsharing.hsadminng.errors.ReferenceNotFoundException;
|
||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactFromResourceConverter;
|
||||
@@ -35,7 +36,7 @@ import static net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationType.
|
||||
import static net.hostsharing.hsadminng.repr.TaggedNumber.cropTag;
|
||||
|
||||
@RestController
|
||||
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
public class HsOfficePartnerController implements HsOfficePartnersApi {
|
||||
|
||||
@Autowired
|
||||
|
@@ -1,6 +1,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.hs.office.generated.api.v1.api.HsOfficePersonsApi;
|
||||
@@ -17,7 +18,7 @@ import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
public class HsOfficePersonController implements HsOfficePersonsApi {
|
||||
|
||||
@Autowired
|
||||
|
@@ -1,6 +1,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.errors.Validate;
|
||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity;
|
||||
@@ -26,6 +27,7 @@ import java.util.function.BiConsumer;
|
||||
import static net.hostsharing.hsadminng.mapper.KeyValueMap.from;
|
||||
|
||||
@RestController
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
public class HsOfficeRelationController implements HsOfficeRelationsApi {
|
||||
|
||||
@Autowired
|
||||
|
@@ -1,6 +1,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.hs.office.bankaccount.HsOfficeBankAccountRepository;
|
||||
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository;
|
||||
@@ -26,7 +27,7 @@ import java.util.function.BiConsumer;
|
||||
import static net.hostsharing.hsadminng.mapper.PostgresDateRange.toPostgresDateRange;
|
||||
|
||||
@RestController
|
||||
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
public class HsOfficeSepaMandateController implements HsOfficeSepaMandatesApi {
|
||||
|
||||
@Autowired
|
||||
|
@@ -1,6 +1,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.mapper.StrictMapper;
|
||||
import net.hostsharing.hsadminng.rbac.generated.api.v1.api.RbacGrantsApi;
|
||||
@@ -17,6 +18,7 @@ import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
public class RbacGrantController implements RbacGrantsApi {
|
||||
|
||||
@Autowired
|
||||
|
@@ -1,6 +1,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.mapper.StrictMapper;
|
||||
import net.hostsharing.hsadminng.rbac.generated.api.v1.api.RbacRolesApi;
|
||||
@@ -13,6 +14,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
public class RbacRoleController implements RbacRolesApi {
|
||||
|
||||
@Autowired
|
||||
|
@@ -1,6 +1,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.mapper.StrictMapper;
|
||||
import net.hostsharing.hsadminng.rbac.generated.api.v1.api.RbacSubjectsApi;
|
||||
@@ -16,6 +17,7 @@ import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
public class RbacSubjectController implements RbacSubjectsApi {
|
||||
|
||||
@Autowired
|
||||
|
@@ -1,5 +1,6 @@
|
||||
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.mapper.StrictMapper;
|
||||
import net.hostsharing.hsadminng.test.generated.api.v1.api.TestCustomersApi;
|
||||
@@ -15,6 +16,7 @@ import jakarta.persistence.PersistenceContext;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
public class TestCustomerController implements TestCustomersApi {
|
||||
|
||||
@Autowired
|
||||
|
@@ -1,5 +1,6 @@
|
||||
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;
|
||||
@@ -15,6 +16,7 @@ import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@SecurityRequirement(name = "casTicket")
|
||||
public class TestPackageController implements TestPackagesApi {
|
||||
|
||||
@Autowired
|
||||
|
@@ -6,7 +6,7 @@ components:
|
||||
currentSubject:
|
||||
name: current-subject
|
||||
in: header
|
||||
required: true
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
description: Identifying name of the current subject (e.g. user).
|
||||
|
@@ -4,6 +4,7 @@ get:
|
||||
tags:
|
||||
- testCustomers
|
||||
operationId: listCustomers
|
||||
|
||||
parameters:
|
||||
- $ref: 'auth.yaml#/components/parameters/currentSubject'
|
||||
- $ref: 'auth.yaml#/components/parameters/assumedRoles'
|
||||
|
@@ -17,7 +17,7 @@ management:
|
||||
# HOWTO: view the effective application configuration properties:
|
||||
# http://localhost:8081/actuator/configprops
|
||||
|
||||
include: info, health, metrics, metric-links, mappings, openapi, swaggerui, configprops, env
|
||||
include: info, health, metrics, metric-links, mappings, openapi, configprops, env
|
||||
endpoint:
|
||||
env:
|
||||
# TODO.spec: check this, maybe set to when_authorized?
|
||||
@@ -37,6 +37,11 @@ spring:
|
||||
url: ${HSADMINNG_POSTGRES_JDBC_URL}
|
||||
username: postgres
|
||||
|
||||
data:
|
||||
rest:
|
||||
# do NOT implicilty expose SpringData repositories as REST-controllers
|
||||
detection-strategy: annotated
|
||||
|
||||
sql:
|
||||
init:
|
||||
mode: never
|
||||
@@ -49,10 +54,6 @@ spring:
|
||||
liquibase:
|
||||
contexts: ${spring.profiles.active}
|
||||
|
||||
# keep this in sync with test/.../application.yml
|
||||
springdoc:
|
||||
use-management-port: true
|
||||
|
||||
hsadminng:
|
||||
postgres:
|
||||
leakproof:
|
||||
@@ -66,3 +67,9 @@ metrics:
|
||||
http:
|
||||
server:
|
||||
requests: true
|
||||
|
||||
logging:
|
||||
level:
|
||||
org:
|
||||
springframework:
|
||||
security: TRACE
|
||||
|
Reference in New Issue
Block a user