Spring security returning 401 with requestmatchers permitAll

When i try registering a new user it only works if i pass credentials of an user that is already registered through basic auth. If i try passing a register user request without auth it returns 401. security config:
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(
auth -> auth.requestMatchers(HttpMethod.POST, "/api/v1/register").permitAll()
.anyRequest().authenticated())
.httpBasic(Customizer.withDefaults())
.oauth2ResourceServer(
conf -> conf.jwt(Customizer.withDefaults()));
return http.build();
}
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(
auth -> auth.requestMatchers(HttpMethod.POST, "/api/v1/register").permitAll()
.anyRequest().authenticated())
.httpBasic(Customizer.withDefaults())
.oauth2ResourceServer(
conf -> conf.jwt(Customizer.withDefaults()));
return http.build();
}
82 Replies
JavaBot
JavaBot4w ago
This post has been reserved for your question.
Hey @Victor! Please use /close or the Close Post button above when your problem is solved. Please remember to follow the help guidelines. This post will be automatically marked as dormant after 300 minutes of inactivity.
TIP: Narrow down your issue to simple and precise questions to maximize the chance that others will reply in here.
Victor
VictorOP4w ago
No description
JavaBot
JavaBot4w ago
💤 Post marked as dormant
This post has been inactive for over 300 minutes, thus, it has been archived. If your question was not answered yet, feel free to re-open this post or create a new one. In case your post is not getting any attention, you can try to use /help ping. Warning: abusing this will result in moderative actions taken against you.
Victor
VictorOP4w ago
anyone?
ayylmao123xdd
ayylmao123xdd4w ago
can you elaborate you mean your request to api v1 register is unauthorized even tho its permitall right show the controller
Victor
VictorOP4w ago
yea exactly
@PostMapping("/register")
public ResponseEntity<Void> postUser(@Validated @RequestBody UserRequest userRequest) {

Optional<User> user = userService.findByUsername(userRequest.username());

if (user.isPresent()) {
throw new UsernameAlreadyTakenException();
}
User newUser = userMapper.toUser(userRequest);
newUser.setPassword(passwordEncoder.encode(userRequest.password()));
userRepository.save(newUser);

return ResponseEntity.status(HttpStatus.OK).build();
}
@PostMapping("/register")
public ResponseEntity<Void> postUser(@Validated @RequestBody UserRequest userRequest) {

Optional<User> user = userService.findByUsername(userRequest.username());

if (user.isPresent()) {
throw new UsernameAlreadyTakenException();
}
User newUser = userMapper.toUser(userRequest);
newUser.setPassword(passwordEncoder.encode(userRequest.password()));
userRepository.save(newUser);

return ResponseEntity.status(HttpStatus.OK).build();
}
if i pass credentials the register goes through, which makes me think the permitAll isnt working
ayylmao123xdd
ayylmao123xdd4w ago
what if you comment out the line with oauth2 does it change anything
Victor
VictorOP4w ago
i'll try it in a bit dont i need that for jwt auth tho?
ayylmao123xdd
ayylmao123xdd4w ago
ye but just for testing to see if removing it helps btw using the if present in your code gonna cause race condition unless you use some locking or just add a unique constraint to the username
Victor
VictorOP4w ago
yea i was going to do that
ayylmao123xdd
ayylmao123xdd4w ago
thats so 🎿 🐝 🦌 then also check if permitting any request to register will throw the same error
Victor
VictorOP4w ago
same results with the oauth line commented you mean without specifying just post?
ayylmao123xdd
ayylmao123xdd4w ago
without specifying http method
Victor
VictorOP4w ago
401 still
ayylmao123xdd
ayylmao123xdd4w ago
quite interesting you sure you put request mapping in the controller
Victor
VictorOP4w ago
when i was googlin this problem i saw someone mentioning something about removing anyrequest authenticated and doing it on a method basis(?) something like this
@RestController
public class UserController {

private final UserRepository userRepository;
private final UserService userService;
private final UserMapper userMapper;
private final BCryptPasswordEncoder passwordEncoder;

public UserController(UserRepository userRepository, UserService userService, UserMapper userMapper, BCryptPasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.userService = userService;
this.userMapper = userMapper;
this.passwordEncoder = passwordEncoder;
}

@PostMapping("/register")
public ResponseEntity<Void> postUser(@Validated @RequestBody UserRequest userRequest) {

Optional<User> user = userService.findByUsername(userRequest.username());

if (user.isPresent()) {
throw new UsernameAlreadyTakenException();
}
User newUser = userMapper.toUser(userRequest);
newUser.setPassword(passwordEncoder.encode(userRequest.password()));
userRepository.save(newUser);

return ResponseEntity.status(HttpStatus.OK).build();
}
}
@RestController
public class UserController {

private final UserRepository userRepository;
private final UserService userService;
private final UserMapper userMapper;
private final BCryptPasswordEncoder passwordEncoder;

public UserController(UserRepository userRepository, UserService userService, UserMapper userMapper, BCryptPasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.userService = userService;
this.userMapper = userMapper;
this.passwordEncoder = passwordEncoder;
}

@PostMapping("/register")
public ResponseEntity<Void> postUser(@Validated @RequestBody UserRequest userRequest) {

Optional<User> user = userService.findByUsername(userRequest.username());

if (user.isPresent()) {
throw new UsernameAlreadyTakenException();
}
User newUser = userMapper.toUser(userRequest);
newUser.setPassword(passwordEncoder.encode(userRequest.password()));
userRepository.save(newUser);

return ResponseEntity.status(HttpStatus.OK).build();
}
}
ayylmao123xdd
ayylmao123xdd4w ago
yea u didnt add request mapping add
@RequestMapping("/api/v1/")
@RequestMapping("/api/v1/")
above rest controller
Victor
VictorOP4w ago
i have it on the application properties i think if the pathing was the problem it wouldnt work with the authentication this controller and the other controller both work normally if i pass authentication
ayylmao123xdd
ayylmao123xdd4w ago
oh try instead of .authenticated do
Victor
VictorOP4w ago
No description
ayylmao123xdd
ayylmao123xdd4w ago
hmmmm show how you set it up in application properties the request mapping
Victor
VictorOP4w ago
server.servlet.context-path=/api/v1
Victor
VictorOP4w ago
No description
ayylmao123xdd
ayylmao123xdd4w ago
o mamma mia ok so do this instead in app properties spring.mvc.servlet.path=/api/v1
Victor
VictorOP4w ago
is that wrong?
ayylmao123xdd
ayylmao123xdd4w ago
use this instead of what u pasted and see if it helps
Victor
VictorOP4w ago
No description
Victor
VictorOP4w ago
i dont think the path is the problem because the controller works still
ayylmao123xdd
ayylmao123xdd4w ago
my bad it was a dot instead of a dash try this
Victor
VictorOP4w ago
it works but i still get 401
ayylmao123xdd
ayylmao123xdd4w ago
weird that shouldve helped
Victor
VictorOP4w ago
whats the difference between that and what i had before?
ayylmao123xdd
ayylmao123xdd4w ago
pathinto is null for the thing you sent ok wait lets call the special forces of java 😱 @dan1st | Daniel can you take a look
Victor
VictorOP4w ago
please 😭 i really dont get whats going on
dan1st
dan1st4w ago
Spring security DEBUG or TRACE logs?
ayylmao123xdd
ayylmao123xdd4w ago
also you got the validated annotation in the controller method btw
dan1st
dan1st4w ago
Can I see the relevatn current code, config, exact error and logs with https://stackoverflow.com/a/47729991/10871900 set?
Victor
VictorOP4w ago
is it ok if i send the logs in .txt?
dan1st
dan1st4w ago
yes
dan1st
dan1st4w ago
Should the endpoint require authentication? Can you show the security config?
Victor
VictorOP4w ago
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {

@Value("${jwt.public.key}")
private RSAPublicKey publicKey;
@Value("${jwt.private.key}")
private RSAPrivateKey privateKey;

private final UserDetailsServiceImpl userDetailsService;

public SecurityConfig(UserDetailsServiceImpl userDetailsService) {
this.userDetailsService = userDetailsService;
}


@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(
auth -> auth.requestMatchers("/api/v1/register").permitAll()
.anyRequest().authenticated())
.httpBasic(Customizer.withDefaults())
.oauth2ResourceServer(
conf -> conf.jwt(Customizer.withDefaults()));
return http.build();
}

@Bean
JwtDecoder jwtDecoder() {
return NimbusJwtDecoder.withPublicKey(publicKey).build();
}

@Bean
JwtEncoder jwtEncoder() {
var jwk = new RSAKey.Builder(this.publicKey).privateKey(privateKey).build();
var jwks = new ImmutableJWKSet<>(new JWKSet(jwk));
return new NimbusJwtEncoder(jwks);
}

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


@Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder(passwordEncoder());
provider.setUserDetailsService(userDetailsService);
return provider;
}

}
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {

@Value("${jwt.public.key}")
private RSAPublicKey publicKey;
@Value("${jwt.private.key}")
private RSAPrivateKey privateKey;

private final UserDetailsServiceImpl userDetailsService;

public SecurityConfig(UserDetailsServiceImpl userDetailsService) {
this.userDetailsService = userDetailsService;
}


@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(
auth -> auth.requestMatchers("/api/v1/register").permitAll()
.anyRequest().authenticated())
.httpBasic(Customizer.withDefaults())
.oauth2ResourceServer(
conf -> conf.jwt(Customizer.withDefaults()));
return http.build();
}

@Bean
JwtDecoder jwtDecoder() {
return NimbusJwtDecoder.withPublicKey(publicKey).build();
}

@Bean
JwtEncoder jwtEncoder() {
var jwk = new RSAKey.Builder(this.publicKey).privateKey(privateKey).build();
var jwks = new ImmutableJWKSet<>(new JWKSet(jwk));
return new NimbusJwtEncoder(jwks);
}

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


@Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder(passwordEncoder());
provider.setUserDetailsService(userDetailsService);
return provider;
}

}
im trying to have no auth needed to register and auth to log in the controller:
@RestController
public class UserController {

private final UserRepository userRepository;
private final UserService userService;
private final UserMapper userMapper;
private final BCryptPasswordEncoder passwordEncoder;

public UserController(UserRepository userRepository, UserService userService, UserMapper userMapper, BCryptPasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.userService = userService;
this.userMapper = userMapper;
this.passwordEncoder = passwordEncoder;
}

@PostMapping("/register")
public ResponseEntity<Void> postUser(@Validated @RequestBody UserRequest userRequest) {

Optional<User> user = userService.findByUsername(userRequest.username());

if (user.isPresent()) {
throw new UsernameAlreadyTakenException();
}
User newUser = userMapper.toUser(userRequest);
newUser.setPassword(passwordEncoder.encode(userRequest.password()));
userRepository.save(newUser);

return ResponseEntity.status(HttpStatus.OK).build();
}
}
@RestController
public class UserController {

private final UserRepository userRepository;
private final UserService userService;
private final UserMapper userMapper;
private final BCryptPasswordEncoder passwordEncoder;

public UserController(UserRepository userRepository, UserService userService, UserMapper userMapper, BCryptPasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.userService = userService;
this.userMapper = userMapper;
this.passwordEncoder = passwordEncoder;
}

@PostMapping("/register")
public ResponseEntity<Void> postUser(@Validated @RequestBody UserRequest userRequest) {

Optional<User> user = userService.findByUsername(userRequest.username());

if (user.isPresent()) {
throw new UsernameAlreadyTakenException();
}
User newUser = userMapper.toUser(userRequest);
newUser.setPassword(passwordEncoder.encode(userRequest.password()));
userRepository.save(newUser);

return ResponseEntity.status(HttpStatus.OK).build();
}
}
dan1st
dan1st4w ago
Can you show the directory structure of your application?
Victor
VictorOP4w ago
its probably a bit messy
Victor
VictorOP4w ago
No description
dan1st
dan1st4w ago
hm, looks fine
ayylmao123xdd
ayylmao123xdd4w ago
maybe its oauth being skibidi and its config
dan1st
dan1st4w ago
It's a POST request, right?
Victor
VictorOP4w ago
yes the request works fine if i pass basic auth of an already registered user
dan1st
dan1st4w ago
you might need CSRF nvm you disabled it
Victor
VictorOP4w ago
yea thats what i found most people suggesting when i searched the issue
dan1st
dan1st4w ago
Does commenting out .httpBasic(Customizer.withDefaults()) change anything? just for testing
Victor
VictorOP4w ago
still get 401
dan1st
dan1st4w ago
Can you check whether your controller is called? wait Can you show your application.properties?
Victor
VictorOP4w ago
jwt.private.key=classpath:app.key jwt.public.key=classpath:app.pub spring.application.name=resell-platform spring.mvc.servlet.path=/api/v1 spring.datasource.url= jdbc:postgresql://localhost:5432/resell spring.datasource.username=postgres spring.datasource.password=postgres spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect logging.level.org.springframework.security=DEBUG
dan1st
dan1st4w ago
You aren't using @RequestMapping, right? for specifying the path on the controller
Victor
VictorOP4w ago
im not but both this controller and the other controller work fine if authentication is passed
Victor
VictorOP4w ago
No description
dan1st
dan1st4w ago
In your security config, replace "/api/v1/register" with "/register"
Victor
VictorOP4w ago
alright that worked lol i definitely had tried that already but i think i had something else messing it up at the time
ayylmao123xdd
ayylmao123xdd4w ago
ye i think it was that servlet too that might be colliding before
Victor
VictorOP4w ago
the old path on the properties?
dan1st
dan1st4w ago
Did you have it before adding spring.mvc.servlet.path=/api/v1?
ayylmao123xdd
ayylmao123xdd4w ago
you can check
dan1st
dan1st4w ago
So the spring.mvc.servlet.path=/api/v1 means Spring adds that everywhere essentially
ayylmao123xdd
ayylmao123xdd4w ago
if it changes anything
Victor
VictorOP4w ago
i was using server.servlet.context-path=/api/v1 instead before
dan1st
dan1st4w ago
so if you do spring.mvc.servlet.path=/api/v1, you should have the /api/v1 on neither the controller nor the security config
Victor
VictorOP4w ago
lets see works with the old path too, i must have messed something up else before thank you both
JavaBot
JavaBot4w ago
If you are finished with your post, please close it. If you are not, please ignore this message. Note that you will not be able to send further messages here after this post have been closed but you will be able to create new posts.
Victor
VictorOP4w ago
@dan1st | Daniel you're the goat
dan1st
dan1st4w ago
btw @ayylmao123xdd if you ping me in the future for things in #java-help, it would be easier for me if you just add a short summary to the message you are pinging me with
Victor
VictorOP4w ago
whats the problem?
ayylmao123xdd
ayylmao123xdd4w ago
it doesnt actually validate the stuff ur sending
Victor
VictorOP4w ago
i just noticed that
ayylmao123xdd
ayylmao123xdd4w ago
use valid instead @Valid
Victor
VictorOP4w ago
valid doesnt show for me, am i missing a dependency?
ayylmao123xdd
ayylmao123xdd4w ago
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> and in the dto you are sending to controller you can use @NotEmpty on string etc
Victor
VictorOP4w ago
@ayylmao123xdd can you accept my friend request real quick? so we dont steer away from the topic of the post too much?
ayylmao123xdd
ayylmao123xdd4w ago
ok
JavaBot
JavaBot4w ago
Post Closed
This post has been closed by <@148254954547576832>.

Did you find this page helpful?