Skip to content

Commit

Permalink
Build and dx (#73)
Browse files Browse the repository at this point in the history
* bump to gradle 8.6, modify classpath for service Run config

* bump gradle github action

* introduce DEV-MODE with configurable user

and compound Run Config to start spring and npm dev on 1 click

* fix test

* @conditional annotations make SecurityConfig cleaner

* remove test data
  • Loading branch information
wisskirchenj authored Feb 13, 2024
1 parent d199379 commit e98db6a
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 45 deletions.
16 changes: 16 additions & 0 deletions .idea/runConfigurations/Flashcards_DEVMODE.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions .idea/runConfigurations/Vue_Server_DEVMODE.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 0 additions & 37 deletions frontend/src/feature/cards/components/CardItemScroller.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,41 +61,4 @@ const openCard = (id: string) => {
console.log("Opening card with id: " + id);
router.push(`/card/${props.categoryId}/${id}`);
}
// ------------------- TEST DATA -------------------
// ---uncomment if on npm run mode - and comment out the fetchCardsPage() call
// const load = async ({done} : {done: Function}) => {
// console.log(`Loading cards ... Now we have ${items.value.length} items.`);
// items.value.push({
// id: "123",
// title: "A math question",
// type: CardType.SIMPLEQA,
// });
// items.value.push({
// id: "456",
// title: "A Java question",
// type: CardType.SINGLE_CHOICE,
// });
// items.value.push({
// id: "456",
// title: "Another Java question",
// type: CardType.SINGLE_CHOICE,
// });
// items.value.push({
// id: "456",
// title: "Another Math question",
// type: CardType.SINGLE_CHOICE,
// });
// items.value.push({
// id: "456",
// title: "Another Python question",
// type: CardType.SINGLE_CHOICE,
// });
// items.value.push({
// id: "456",
// title: "A Python question",
// type: CardType.SINGLE_CHOICE,
// });
// done('ok');
// }
// load({done: console.log});
</script>
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
package org.hyperskill.community.flashcards.common;

import lombok.RequiredArgsConstructor;
import org.springframework.core.env.Environment;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class AuthenticationResolver {

private final Environment env;

public String resolveUsername() {
if (Boolean.TRUE.equals(env.getProperty("DEV_MODE", Boolean.class, false))) {
return env.getProperty("DEV_USER", "test1@test.com");
}
var authentication = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return switch (authentication) {
case OidcUser oidcUser -> oidcUser.getSubject();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.hyperskill.community.flashcards.config;

import lombok.extern.slf4j.Slf4j;
import org.hyperskill.community.flashcards.registration.User;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.MongoTemplate;
Expand All @@ -13,42 +15,76 @@
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.List;
import java.util.Optional;

import static org.springframework.security.config.Customizer.withDefaults;

/**
* new Spring security 6.0 style provision of SecurityFilterChain bean with the security configuration,
* Spring security 6.x style provision of SecurityFilterChain bean with the security configuration,
* as well as PasswordProvider and AuthenticationManager that makes use of our UserDetails persistence.
*/
@Configuration
@EnableWebSecurity
@Slf4j
public class WebSecurityConfiguration {

@Bean
@ConditionalOnProperty(name = "DEV_MODE", havingValue = "false", matchIfMissing = true)
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf(CsrfConfigurer::disable)
.oauth2ResourceServer(auth -> auth.jwt(withDefaults()))
.oauth2Login(withDefaults())
.oauth2Client(withDefaults())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/register.html", "/js/register.js", "/css/register.css").permitAll()
.requestMatchers(HttpMethod.POST, "/api/register").permitAll()
.anyRequest().authenticated())
.oauth2Login(withDefaults())
.oauth2Client(withDefaults())
.build();
.anyRequest().authenticated()
).build();
}

@Bean
public UserDetailsService userDetailsService(MongoTemplate mongoTemplate) {
return username ->
Optional.ofNullable(mongoTemplate.findById(username, User.class))
.orElseThrow(() -> new UsernameNotFoundException("User not found."));
Optional.ofNullable(mongoTemplate.findById(username, User.class))
.orElseThrow(() -> new UsernameNotFoundException("User not found."));
}

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

@Bean
@ConditionalOnProperty(name = "DEV_MODE", havingValue = "true")
public SecurityFilterChain filterChainDevMode(HttpSecurity http) throws Exception {
log.warn("Running in DEV_MODE, permitting all requests.");
return http
.csrf(CsrfConfigurer::disable)
.cors(withDefaults())
.authorizeHttpRequests(
auth -> auth.anyRequest().permitAll()
).build();
}

@Bean
@ConditionalOnProperty(name = "DEV_MODE", havingValue = "true")
public CorsConfigurationSource corsConfigurationSource() {
log.info("Configuring CORS for DEV MODE");
var configuration = new CorsConfiguration();
configuration.setAllowedOrigins(List.of("http://localhost:3000"));
configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
configuration.setAllowedHeaders(List.of("Authorization",
"Access-Control-Allow-Origin", "Content-Type"));
configuration.setExposedHeaders(List.of("Authorization",
"Access-Control-Allow-Origin", "Content-Type"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/api/**", configuration);
return source;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.junit.jupiter.MockitoSettings;
import org.springframework.core.env.Environment;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
Expand All @@ -29,9 +31,12 @@ class AuthenticationResolverTest {

AuthenticationResolver resolver;

@Mock
Environment env;

@BeforeEach
void setup() {
resolver = new AuthenticationResolver();
resolver = new AuthenticationResolver(env);
}

static Stream<Arguments> whenJwtOrOidcAuthentication_resolverWorks() {
Expand Down

0 comments on commit e98db6a

Please sign in to comment.