Skip to content

Commit

Permalink
mix of authentication, backend, frontend works
Browse files Browse the repository at this point in the history
  • Loading branch information
iannagasen committed Aug 23, 2024
1 parent 2dfb24e commit 5b33f20
Show file tree
Hide file tree
Showing 58 changed files with 330 additions and 1,360 deletions.
6 changes: 3 additions & 3 deletions src/backend/api/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ dependencies {
testCompileOnly 'org.projectlombok:lombok:1.18.30'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.30'

implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.security:spring-security-oauth2-resource-server'
implementation 'org.springframework.security:spring-security-oauth2-jose'
// implementation 'org.springframework.boot:spring-boot-starter-security'
// implementation 'org.springframework.security:spring-security-oauth2-resource-server'
// implementation 'org.springframework.security:spring-security-oauth2-jose'

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import java.util.List;

import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties.Jwt;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.userdetails.UserDetails;
// import org.springframework.security.core.annotation.AuthenticationPrincipal;
// import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
Expand All @@ -27,6 +28,6 @@ public interface OrderRestController {
Mono<Inventory> getOrderInventory(@PathVariable(value = "productId") Long productId);

@GetMapping(value = "/orders", produces = "application/json")
Mono<List<PurchaseOrder>> getOrders(@AuthenticationPrincipal Jwt userDetails, @RequestParam(name = "type", defaultValue = "ALL") GetOrdersType type);
Mono<List<PurchaseOrder>> getOrders(@RequestParam(name = "type", defaultValue = "ALL") GetOrdersType type);

}
Original file line number Diff line number Diff line change
Expand Up @@ -337,8 +337,8 @@ public WebMvcConfigurer corsConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:4200")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*");
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;

import dev.agasen.ecom.api.auth.resourceserver.EcomJwtAuthenticationConverter;
import dev.agasen.ecom.inventory.auth.resourceserver.EcomJwtAuthenticationConverter;



@SpringBootApplication(scanBasePackages = "dev.agasen")
public class InventoryServiceApplication {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package dev.agasen.ecom.inventory.auth.resourceserver;

import java.util.Collection;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;



public class EcomAuthentication extends JwtAuthenticationToken {
/**
*
* A Custom Authentication object used to reshape the JWT token
*
*/

private final String priority;

public EcomAuthentication(Jwt jwt, Collection<? extends GrantedAuthority> authorities, String priority) {
super(jwt, authorities);

// we are adding a new field to the JwtAuthenticationToken class
// this priority field is in a claim in the JWT token
this.priority = priority;
}

public String getPriority() {
return priority;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package dev.agasen.ecom.inventory.auth.resourceserver;

import java.util.List;

import org.springframework.core.convert.converter.Converter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.stereotype.Component;

import reactor.core.publisher.Mono;

@Component
public class EcomJwtAuthenticationConverter implements Converter<Jwt, Mono<EcomAuthentication>>{

@Override
public Mono<EcomAuthentication> convert(Jwt source) {
List<GrantedAuthority> authorities = List.of(() -> "read");

String priority = String.valueOf(source.getClaims().get("priority"));

return Mono.just(new EcomAuthentication(source, authorities, priority));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,23 @@
import static org.mockito.Mockito.when;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.reactive.server.WebTestClient;

import dev.agasen.ecom.inventory.BaseIntegrationTest;
import dev.agasen.ecom.inventory.messaging.OrderEventRouterConfig;
import dev.agasen.ecom.inventory.repository.InventoryRepository;
import dev.agasen.ecom.inventory.repository.InventoryUpdateRepository;
import dev.agasen.ecom.inventory.rest.service.InventoryQueryService;
import dev.agasen.ecom.util.mongo.SequenceGeneratorService;

@WebFluxTest(controllers = InventoryController.class)
// @Import(InventoryQueryService.class)
public class InventoryControllerTest /* extends BaseIntegrationTest */ {

@Autowired WebTestClient webTestClient;
@MockBean InventoryQueryService queryService;
// @MockBean InventoryUpdateRepository repository;
// @MockBean OrderEventRouterConfig orderEventRouterConfig;
// @MockBean InventoryRepository inventoryRepository;
// @MockBean SequenceGeneratorService sequenceGeneratorService;

@Test
void testDeduct() {

}
}

@Test
void testGetInventories() {
Expand All @@ -56,4 +41,4 @@ void testGetInventory() {
void testGetInventoryHistory() {

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import dev.agasen.ecom.api.auth.resourceserver.EcomAuthentication;
import dev.agasen.ecom.order.auth.resourceserver.EcomAuthentication;
import lombok.extern.slf4j.Slf4j;


Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package dev.agasen.ecom.api.auth.resourceserver;
package dev.agasen.ecom.order.auth.resourceserver;

import java.util.Collection;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package dev.agasen.ecom.api.auth.resourceserver;
package dev.agasen.ecom.order.auth.resourceserver;

import java.util.List;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ public Mono<Inventory> getOrderInventory(Long productId) {
}

@Override
public Mono<List<PurchaseOrder>> getOrders(@AuthenticationPrincipal Jwt jwt, GetOrdersType type) {
log.info("Jwt is {}", jwt);
public Mono<List<PurchaseOrder>> getOrders(GetOrdersType type) {
// log.info("Jwt is {}", jwt);
return orderService.getOrders(type)
.map(PurchaseOrderEntity::toRestModel)
.collectList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,39 @@
import java.util.Collection;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity.CorsSpec;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.reactive.config.CorsRegistry;
import org.springframework.web.reactive.config.WebFluxConfigurer;

import dev.agasen.ecom.api.auth.resourceserver.EcomJwtAuthenticationConverter;
import dev.agasen.ecom.order.auth.resourceserver.EcomJwtAuthenticationConverter;
import dev.agasen.ecom.util.security.AuthenticationFacade;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Mono;

import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;



@Configuration
@Slf4j
Expand Down Expand Up @@ -45,8 +66,7 @@ public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) th
http.oauth2ResourceServer( // configure the app as resoruce server
c -> c.jwt( // configure the app to use JWT
j -> j.jwkSetUri(keySsetUri) // configure the public key set URL that the reesource server will use to validate JWTs
.jwtAuthenticationConverter(new EcomJwtAuthenticationConverter())
)
.jwtAuthenticationConverter(new EcomJwtAuthenticationConverter()))
);

/**
Expand All @@ -66,21 +86,52 @@ public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) th
.anyExchange().authenticated()
);

// http.cors((Customizer<CorsSpec>) CorsSpec::disable);

return http.build();
}


// @Bean
// public WebFluxConfigurer corsConfigurer() {
// return new WebFluxConfigurer() {
// @Override
// public void addCorsMappings(CorsRegistry registry) {
// registry.addMapping("/**")
// // .allowCredentials(true)
// .allowedOrigins("*")
// .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
// .allowedHeaders("*");

// }
// };
// }

@Bean
public WebFluxConfigurer corsConfigurer() {
return new WebFluxConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:4200")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*");
@Order(Ordered.HIGHEST_PRECEDENCE)
public WebFilter corsFilter() {

final String ALLOWED_HEADERS = "*";
final String ALLOWED_METHODS = "GET, PUT, POST, DELETE, OPTIONS";
final String ALLOWED_ORIGIN = "*";
final String MAX_AGE = "3600";

return (ServerWebExchange ctx, WebFilterChain chain) -> {
ServerHttpRequest request = ctx.getRequest();
if (CorsUtils.isCorsRequest(request)) {
ServerHttpResponse response = ctx.getResponse();
HttpHeaders headers = response.getHeaders();
headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
headers.add("Access-Control-Max-Age", MAX_AGE);
headers.add("Access-Control-Allow-Headers",ALLOWED_HEADERS);
if (request.getMethod() == HttpMethod.OPTIONS) {
response.setStatusCode(HttpStatus.OK);
return Mono.empty();
}
}
return chain.filter(ctx);
};
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package dev.agasen.ecom.order.service;

import java.util.function.Function;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand Down Expand Up @@ -52,7 +57,9 @@ public Mono<PurchaseOrderEntity> placeOrder(CreateOrderRequest req) {

@Override
public Flux<PurchaseOrderEntity> getOrders(GetOrdersType type) {
return authFacade.getAuthentication().doOnNext(auth -> log.info("Auth: {}", auth)).thenMany(purchaseOrderRepo.findAll());
return ReactiveSecurityContextHolder.getContext()
.map((Function<? super SecurityContext, ? extends Authentication>) SecurityContext::getAuthentication)
.doOnNext(auth -> log.info("Auth: {}", auth)).thenMany(purchaseOrderRepo.findAll());
}

}
2 changes: 1 addition & 1 deletion src/backend/util/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ dependencies {
testCompileOnly 'org.projectlombok:lombok:1.18.30'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.30'

implementation 'org.springframework.boot:spring-boot-starter-security'
// implementation 'org.springframework.boot:spring-boot-starter-security'
}

dependencyManagement {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

import java.util.function.Function;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
// import org.springframework.security.core.Authentication;
// import org.springframework.security.core.context.ReactiveSecurityContextHolder;
// import org.springframework.security.core.context.SecurityContext;
// import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;
Expand All @@ -15,13 +15,13 @@
@Slf4j
public class AuthenticationFacade {

public Mono<Authentication> getAuthentication() {
log.info("context: {}", SecurityContextHolder.getContext());
return ReactiveSecurityContextHolder.getContext().map((Function<? super SecurityContext, ? extends Authentication>) SecurityContext::getAuthentication);
}
// public Mono<Authentication> getAuthentication() {
// log.info("context: {}", SecurityContextHolder.getContext());
// return ReactiveSecurityContextHolder.getContext().map((Function<? super SecurityContext, ? extends Authentication>) SecurityContext::getAuthentication);
// }

public void setAuthentication(Authentication authentication) {
SecurityContextHolder.getContext().setAuthentication(authentication);
}
// public void setAuthentication(Authentication authentication) {
// SecurityContextHolder.getContext().setAuthentication(authentication);
// }

}
Loading

0 comments on commit 5b33f20

Please sign in to comment.