Skip to content
Snippets Groups Projects
Commit da52e64c authored by Martin Weise's avatar Martin Weise
Browse files

Merge branch '395-support-basic-authentication-2' into 'dev'

Resolve "Support basic authentication"

See merge request !241
parents e0b64e86 c5bf8134
No related branches found
No related tags found
5 merge requests!250Master,!246Dev,!244Dev,!243Dev,!241Resolve "Support basic authentication"
Showing
with 145 additions and 48 deletions
......@@ -75,7 +75,7 @@ public class ImageEndpoint {
@Transactional
@Observed(name = "dbr_image_create")
@PreAuthorize("hasAuthority('create-image')")
@Operation(summary = "Create image", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Create image", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "201",
description = "Created image",
......@@ -137,7 +137,7 @@ public class ImageEndpoint {
@Transactional
@Observed(name = "dbr_image_update")
@PreAuthorize("hasAuthority('modify-image')")
@Operation(summary = "Update some image", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Update some image", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "202",
description = "Updated image successfully",
......@@ -166,7 +166,7 @@ public class ImageEndpoint {
@Transactional
@Observed(name = "dbr_image_delete")
@PreAuthorize("hasAuthority('delete-image')")
@Operation(summary = "Delete some image", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Delete some image", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "202",
description = "Deleted image successfully",
......
......@@ -90,7 +90,7 @@ public class OntologyEndpoint {
@PostMapping
@PreAuthorize("hasAuthority('create-ontology')")
@Observed(name = "dbr_ontologies_create")
@Operation(summary = "Register a new ontology", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Register a new ontology", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "201",
description = "Registered ontology successfully",
......@@ -110,7 +110,7 @@ public class OntologyEndpoint {
@PutMapping("/{id}")
@PreAuthorize("hasAuthority('update-ontology')")
@Observed(name = "dbr_ontologies_update")
@Operation(summary = "Update an ontology", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Update an ontology", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "202",
description = "Updated ontology successfully",
......@@ -136,7 +136,7 @@ public class OntologyEndpoint {
@DeleteMapping("/{id}")
@PreAuthorize("hasAuthority('delete-ontology')")
@Observed(name = "dbr_ontologies_delete")
@Operation(summary = "Delete an ontology", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Delete an ontology", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "202",
description = "Deleted ontology successfully",
......@@ -158,7 +158,7 @@ public class OntologyEndpoint {
@GetMapping("/{id}/entity")
@PreAuthorize("hasAuthority('execute-semantic-query')")
@Observed(name = "dbr_ontologies_entities_find")
@Operation(summary = "Find entities", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Find entities", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
description = "Found entities",
......
......@@ -163,7 +163,7 @@ public class PersistenceEndpoint {
@Transactional
@Observed(name = "dbr_pid_delete")
@PreAuthorize("hasAuthority('delete-identifier')")
@Operation(summary = "Delete some identifier", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Delete some identifier", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "202",
description = "Deleted identifier"),
......
......@@ -57,7 +57,7 @@ public class QueryEndpoint {
@Transactional(readOnly = true)
@Observed(name = "dbr_query_execute")
@PreAuthorize("hasAuthority('execute-query')")
@Operation(summary = "Execute query", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Execute query", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "202",
description = "Executed query",
......@@ -121,7 +121,7 @@ public class QueryEndpoint {
@GetMapping("/{queryId}/data")
@Transactional(readOnly = true)
@Observed(name = "dbr_query_reexecute")
@Operation(summary = "Re-execute some query", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Re-execute some query", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "202",
description = "Executed query",
......@@ -181,7 +181,7 @@ public class QueryEndpoint {
@GetMapping("/{queryId}/data/count")
@Transactional(readOnly = true)
@Observed(name = "dbr_query_reexecute_count")
@Operation(summary = "Re-execute some query", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Re-execute some query", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "202",
description = "Executed query",
......@@ -228,7 +228,7 @@ public class QueryEndpoint {
@GetMapping("/{queryId}/export")
@Transactional(readOnly = true)
@Observed(name = "dbr_query_export")
@Operation(summary = "Exports some query", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Exports some query", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
description = "Executed query"),
......
......@@ -93,7 +93,7 @@ public class SemanticsEndpoint {
@Transactional(readOnly = true)
@PreAuthorize("hasAuthority('table-semantic-analyse')")
@Observed(name = "dbr_semantic_table_analyse")
@Operation(summary = "Suggest table semantics", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Suggest table semantics", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
description = "Suggested table semantics successfully",
......@@ -130,7 +130,7 @@ public class SemanticsEndpoint {
@Transactional(readOnly = true)
@PreAuthorize("hasAuthority('table-semantic-analyse')")
@Observed(name = "dbr_semantic_column_analyse")
@Operation(summary = "Suggest table column semantics", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Suggest table column semantics", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
description = "Suggested table column semantics successfully",
......
......@@ -74,7 +74,7 @@ public class StoreEndpoint {
@GetMapping
@Transactional(readOnly = true)
@Observed(name = "dbr_queries_findall")
@Operation(summary = "Find queries", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Find queries", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
description = "List queries",
......@@ -151,7 +151,7 @@ public class StoreEndpoint {
@GetMapping("/{queryId}")
@Transactional(readOnly = true)
@Observed(name = "dbr_queries_find")
@Operation(summary = "Find some query", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Find some query", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
description = "List queries",
......@@ -212,7 +212,7 @@ public class StoreEndpoint {
@Transactional(readOnly = true)
@PreAuthorize("hasAuthority('persist-query')")
@Observed(name = "dbr_query_persist")
@Operation(summary = "Persist some query", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Persist some query", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
description = "Persist query successful",
......
......@@ -49,7 +49,7 @@ public class TableColumnEndpoint {
@Transactional
@PreAuthorize("hasAuthority('modify-table-column-semantics') or hasAuthority('modify-foreign-table-column-semantics')")
@Observed(name = "dbr_semantics_column_save")
@Operation(summary = "Update a table column semantic mapping", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Update a table column semantic mapping", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "202",
description = "Updated column semantics successfully",
......
......@@ -5,7 +5,6 @@ import at.tuwien.api.database.query.ImportDto;
import at.tuwien.api.database.query.QueryResultDto;
import at.tuwien.api.database.table.TableCsvDeleteDto;
import at.tuwien.api.database.table.TableCsvDto;
import at.tuwien.api.database.table.columns.ColumnDto;
import at.tuwien.api.error.ApiErrorDto;
import at.tuwien.entities.database.Database;
import at.tuwien.exception.*;
......@@ -15,6 +14,7 @@ import at.tuwien.utils.PrincipalUtil;
import at.tuwien.utils.UserUtil;
import at.tuwien.validation.EndpointValidator;
import io.micrometer.observation.annotation.Observed;
import io.swagger.v3.oas.annotations.ExternalDocumentation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
......@@ -55,7 +55,8 @@ public class TableDataEndpoint {
@Transactional
@Observed(name = "dbr_table_data_insert")
@PreAuthorize("hasAuthority('insert-table-data')")
@Operation(summary = "Insert data", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Insert data", description = "Insert data directly as key-value map tuple",
security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "202",
description = "Inserted data successfully"),
......@@ -94,7 +95,8 @@ public class TableDataEndpoint {
@Transactional
@PreAuthorize("hasAuthority('delete-table-data')")
@Observed(name = "dbr_table_data_delete")
@Operation(summary = "Delete data", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Delete data", description = "Delete a tuples that match a key-value map",
security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "202",
description = "Deleted table data successfully"),
......@@ -133,7 +135,7 @@ public class TableDataEndpoint {
@Transactional
@PreAuthorize("hasAuthority('insert-table-data')")
@Observed(name = "dbr_table_data_import")
@Operation(summary = "Insert data from csv", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Insert data from csv", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "202",
description = "Import table data successfully"),
......@@ -181,7 +183,7 @@ public class TableDataEndpoint {
@RequestMapping(method = {RequestMethod.GET, RequestMethod.HEAD})
@Transactional(readOnly = true)
@Observed(name = "dbr_table_data_findall")
@Operation(summary = "Find data", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Find data", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "202",
description = "Get table data successfully"),
......@@ -237,7 +239,7 @@ public class TableDataEndpoint {
@GetMapping("/count")
@Transactional(readOnly = true)
@Observed(name = "dbr_table_data_countall")
@Operation(summary = "Find data", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Find data", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "202",
description = "Get table data count successfully"),
......
......@@ -61,7 +61,7 @@ public class TableEndpoint {
@GetMapping
@Transactional(readOnly = true)
@Observed(name = "dbr_tables_findall")
@Operation(summary = "List all tables", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "List all tables", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
description = "List tables",
......@@ -97,7 +97,7 @@ public class TableEndpoint {
@Transactional
@PreAuthorize("hasAuthority('create-table')")
@Observed(name = "dbr_table_create")
@Operation(summary = "Create a table", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Create a table", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "201",
description = "Created a new table",
......@@ -150,7 +150,7 @@ public class TableEndpoint {
@GetMapping("/{tableId}")
@Transactional(readOnly = true)
@Observed(name = "dbr_tables_find")
@Operation(summary = "Get information about table", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Get information about table", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
description = "Find table successfully",
......@@ -193,7 +193,7 @@ public class TableEndpoint {
@Transactional
@PreAuthorize("hasAuthority('delete-table') or hasAuthority('delete-foreign-table')")
@Observed(name = "dbr_table_delete")
@Operation(summary = "Delete a table", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Delete a table", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "202",
description = "Delete table successfully",
......
......@@ -39,7 +39,7 @@ public class TableHistoryEndpoint {
@RequestMapping(method = {RequestMethod.GET, RequestMethod.HEAD})
@Transactional(readOnly = true)
@Observed(name = "dbr_table_history_findall")
@Operation(summary = "Find all history", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Find all history", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
description = "Find table history successfully",
......
......@@ -147,7 +147,7 @@ public class UserEndpoint {
@Transactional
@PreAuthorize("isAuthenticated() or hasAuthority('find-user')")
@Observed(name = "dbr_user_find")
@Operation(summary = "Get a user info", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Get a user info", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
description = "Found user",
......@@ -189,7 +189,7 @@ public class UserEndpoint {
@Transactional
@PreAuthorize("hasAuthority('modify-user-information')")
@Observed(name = "dbr_user_modify")
@Operation(summary = "Modify user information", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Modify user information", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "202",
description = "Modified user information",
......@@ -240,7 +240,7 @@ public class UserEndpoint {
@Transactional
@PreAuthorize("hasAuthority('modify-user-theme')")
@Observed(name = "dbr_user_theme_modify")
@Operation(summary = "Modify user theme", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Modify user theme", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "202",
description = "Modified user theme",
......@@ -285,7 +285,7 @@ public class UserEndpoint {
@Transactional
@PreAuthorize("isAuthenticated()")
@Observed(name = "dbr_user_password_modify")
@Operation(summary = "Modify user password", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Modify user password", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "202",
description = "Modified user password",
......
......@@ -62,7 +62,7 @@ public class ViewEndpoint {
@GetMapping
@Transactional(readOnly = true)
@Observed(name = "dbr_views_findall")
@Operation(summary = "Find all views", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Find all views", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
description = "Find views successfully",
......@@ -93,7 +93,7 @@ public class ViewEndpoint {
@Transactional
@PreAuthorize("hasAuthority('create-database-view')")
@Observed(name = "dbr_view_create")
@Operation(summary = "Create a view", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Create a view", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "201",
description = "Create view successfully",
......@@ -160,7 +160,7 @@ public class ViewEndpoint {
@GetMapping("/{viewId}")
@Transactional(readOnly = true)
@Observed(name = "dbr_view_find")
@Operation(summary = "Find one view", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Find one view", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
description = "Find view successfully",
......@@ -194,7 +194,7 @@ public class ViewEndpoint {
@Transactional
@PreAuthorize("hasAuthority('delete-database-view')")
@Observed(name = "dbr_view_delete")
@Operation(summary = "Delete one view", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Delete one view", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
description = "Delete view successfully",
......@@ -250,7 +250,7 @@ public class ViewEndpoint {
@GetMapping("/{viewId}/data")
@Transactional(readOnly = true)
@Observed(name = "dbr_view_data_findall")
@Operation(summary = "Find view data", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Find view data", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
description = "Find data successfully",
......@@ -307,7 +307,7 @@ public class ViewEndpoint {
@GetMapping("/{viewId}/data/count")
@Transactional(readOnly = true)
@Observed(name = "dbr_view_data_count")
@Operation(summary = "Find view data count", security = @SecurityRequirement(name = "bearerAuth"))
@Operation(summary = "Find view data count", security = {@SecurityRequirement(name = "bearerAuth"), @SecurityRequirement(name = "basicAuth")})
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
description = "Count data successfully",
......
......@@ -40,7 +40,7 @@ spring:
loadbalancer.ribbon.enabled: false
management.endpoints.web.exposure.include: health,info,prometheus
server:
port: 9099
port: 19099
logging:
pattern.console: "%d %highlight(%-5level) %msg%n"
level:
......@@ -66,6 +66,7 @@ fda:
endpoint: "http://authentication-service:8080"
username: fda
password: fda
clientSecret: MUwRc7yfXSJwX8AdRMWaQC3Nep1VjwgG
unsupported: \*,AVG,BIT_AND,BIT_OR,BIT_XOR,COUNT,COUNTDISTINCT,GROUP_CONCAT,JSON_ARRAYAGG,JSON_OBJECTAGG,MAX,MIN,STD,STDDEV,STDDEV_POP,STDDEV_SAMP,SUM,VARIANCE,VAR_POP,VAR_SAMP,--
website: http://localhost
minConcurrent: 1
......
......@@ -79,6 +79,7 @@ fda:
endpoint: "${KEYCLOAK_HOST}"
username: "${KEYCLOAK_ADMIN}"
password: "${KEYCLOAK_ADMIN_PASSWORD}"
clientSecret: "${KEYCLOAK_CLIENT_SECRET}"
unsupported: "${NOT_SUPPORTED_KEYWORDS}"
website: "${WEBSITE}"
minConcurrent: "${MIN_CONCURRENT_CONSUMERS}"
......
......@@ -6,6 +6,7 @@ import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.Verification;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
......@@ -56,6 +57,10 @@ public class AuthTokenFilter extends OncePerRequestFilter {
}
public UserDetails verifyJwt(String token) throws ServletException {
return verifyJwt(token, true);
}
public UserDetails verifyJwt(String token, boolean strict) throws ServletException {
final KeyFactory kf;
try {
kf = KeyFactory.getInstance("RSA");
......@@ -72,10 +77,12 @@ public class AuthTokenFilter extends OncePerRequestFilter {
throw new ServletException("Provided public key is invalid", e);
}
final Algorithm algorithm = Algorithm.RSA256(pubKey, null);
JWTVerifier verifier = JWT.require(algorithm)
.withIssuer(issuer)
.withAudience("spring")
.build();
Verification verification = JWT.require(algorithm)
.withAudience("spring");
if (strict) {
verification = verification.withIssuer(issuer);
}
final JWTVerifier verifier = verification.build();
final DecodedJWT jwt = verifier.verify(token);
final RealmAccessDto realmAccess = jwt.getClaim("realm_access").as(RealmAccessDto.class);
return UserDetailsDto.builder()
......
package at.tuwien.auth;
import at.tuwien.api.keycloak.TokenDto;
import at.tuwien.exception.AccessDeniedException;
import at.tuwien.exception.KeycloakRemoteException;
import at.tuwien.gateway.KeycloakGateway;
import jakarta.servlet.ServletException;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
@Log4j2
@Component
public class BasicAuthenticationProvider implements AuthenticationManager {
private final AuthTokenFilter authTokenFilter;
private final KeycloakGateway keycloakGateway;
@Autowired
public BasicAuthenticationProvider(AuthTokenFilter authTokenFilter, KeycloakGateway keycloakGateway) {
this.authTokenFilter = authTokenFilter;
this.keycloakGateway = keycloakGateway;
}
@Override
public Authentication authenticate(Authentication auth) throws AuthenticationException {
try {
final TokenDto tokenDto = keycloakGateway.obtainUserToken(auth.getName(), auth.getCredentials().toString());
final UserDetails userDetails = authTokenFilter.verifyJwt(tokenDto.getAccessToken(), false);
log.debug("authenticated user {}", userDetails);
return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
} catch (AccessDeniedException | KeycloakRemoteException | ServletException e) {
throw new BadCredentialsException("Failed to authenticate with authentication service", e);
}
}
}
......@@ -21,6 +21,9 @@ public class KeycloakConfig {
@Value("${fda.keycloak.password}")
private String keycloakPassword;
@Value("${fda.keycloak.clientSecret}")
private String keycloakClientSecret;
@Bean("keycloakRestTemplate")
public RestTemplate brokerRestTemplate() {
final RestTemplate restTemplate = new RestTemplate();
......
package at.tuwien.config;
import at.tuwien.auth.AuthTokenFilter;
import at.tuwien.auth.BasicAuthenticationProvider;
import at.tuwien.gateway.KeycloakGateway;
import io.swagger.v3.oas.annotations.enums.SecuritySchemeType;
import io.swagger.v3.oas.annotations.security.SecurityScheme;
import jakarta.servlet.http.HttpServletResponse;
......@@ -12,6 +14,7 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.web.cors.CorsConfiguration;
......@@ -27,6 +30,11 @@ import org.springframework.web.filter.CorsFilter;
bearerFormat = "JWT",
scheme = "bearer"
)
@SecurityScheme(
name = "basicAuth",
type = SecuritySchemeType.HTTP,
scheme = "basic"
)
public class WebSecurityConfig {
@Bean
......@@ -35,7 +43,7 @@ public class WebSecurityConfig {
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
public SecurityFilterChain filterChain(HttpSecurity http, KeycloakGateway keycloakGateway) throws Exception {
final OrRequestMatcher internalEndpoints = new OrRequestMatcher(
new AntPathRequestMatcher("/actuator/**", "GET"),
new AntPathRequestMatcher("/v3/api-docs.yaml"),
......@@ -77,6 +85,9 @@ public class WebSecurityConfig {
http.addFilterBefore(authTokenFilter(),
UsernamePasswordAuthenticationFilter.class
);
http.addFilterBefore(new BasicAuthenticationFilter(new BasicAuthenticationProvider(authTokenFilter(), keycloakGateway)),
UsernamePasswordAuthenticationFilter.class
);
return http.build();
}
......
package at.tuwien.gateway;
import at.tuwien.api.keycloak.TokenDto;
import at.tuwien.api.keycloak.UserCreateDto;
import at.tuwien.api.keycloak.UserDto;
import at.tuwien.api.user.UserPasswordDto;
......@@ -9,6 +10,8 @@ import java.util.UUID;
public interface KeycloakGateway {
TokenDto obtainUserToken(String username, String password) throws AccessDeniedException, KeycloakRemoteException;
/**
* Creates a user at the Authentication Service with given credentials.
*
......
......@@ -48,10 +48,37 @@ public class KeycloakGatewayImpl implements KeycloakGateway {
response = restTemplate.exchange(url, HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class);
} catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) {
log.error("Failed to obtain admin token: {}", e.getMessage());
throw new AccessDeniedException("Failed to obtain admin token: " + e.getMessage());
throw new AccessDeniedException("Failed to obtain admin token: " + e.getMessage(), e);
} catch (Exception e) {
log.error("Failed to create user: remote host answered unexpected: {}", e.getMessage());
throw new KeycloakRemoteException("Failed to create user: remote host answered unexpected: " + e.getMessage(), e);
log.error("Failed to obtain admin token: remote host answered unexpected: {}", e.getMessage(), e);
throw new KeycloakRemoteException("Failed to obtain admin token: remote host answered unexpected: " + e.getMessage(), e);
}
return response.getBody();
}
@Override
public TokenDto obtainUserToken(String username, String password) throws AccessDeniedException, KeycloakRemoteException {
final HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
final MultiValueMap<String, String> payload = new LinkedMultiValueMap<>();
payload.add("username", username);
payload.add("password", password);
payload.add("grant_type", "password");
payload.add("scope", "openid roles attributes");
payload.add("client_id", "dbrepo-client");
payload.add("client_secret", keycloakConfig.getKeycloakClientSecret());
final String url = keycloakConfig.getKeycloakEndpoint() + "/realms/dbrepo/protocol/openid-connect/token";
log.debug("request user token from url {}", url);
final ResponseEntity<TokenDto> response;
try {
response = new RestTemplate()
.exchange(url, HttpMethod.POST, new HttpEntity<>(payload, headers), TokenDto.class);
} catch (ResourceAccessException | HttpServerErrorException.ServiceUnavailable e) {
log.error("Failed to obtain user token: {}", e.getMessage());
throw new AccessDeniedException("Failed to obtain user token: " + e.getMessage(), e);
} catch (Exception e) {
log.error("Failed to obtain user token: remote host answered unexpected: {}", e.getMessage(), e);
throw new KeycloakRemoteException("Failed to obtain user token: remote host answered unexpected: " + e.getMessage(), e);
}
return response.getBody();
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment