Implement token-based authentication
This commit is contained in:
parent
7237e12363
commit
5a9c845b3f
15 changed files with 280 additions and 12 deletions
|
@ -27,7 +27,7 @@ jar {
|
||||||
description = "twigs-server"
|
description = "twigs-server"
|
||||||
}
|
}
|
||||||
|
|
||||||
mainClassName = "com.wbrawner.budgetserver.BudgetServerApplication"
|
mainClassName = "com.wbrawner.budgetserver.TwigsServerApplication"
|
||||||
|
|
||||||
sourceCompatibility = 14
|
sourceCompatibility = 14
|
||||||
targetCompatibility = 14
|
targetCompatibility = 14
|
||||||
|
|
|
@ -2,10 +2,12 @@ package com.wbrawner.budgetserver;
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class BudgetServerApplication {
|
@EnableScheduling
|
||||||
|
public class TwigsServerApplication {
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(BudgetServerApplication.class, args);
|
SpringApplication.run(TwigsServerApplication.class, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -3,10 +3,11 @@ package com.wbrawner.budgetserver;
|
||||||
import com.wbrawner.budgetserver.user.User;
|
import com.wbrawner.budgetserver.user.User;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
|
||||||
|
import java.security.SecureRandom;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
import java.util.UUID;
|
import java.util.Random;
|
||||||
|
|
||||||
public final class Utils {
|
public final class Utils {
|
||||||
private static final int[] CALENDAR_FIELDS = new int[]{
|
private static final int[] CALENDAR_FIELDS = new int[]{
|
||||||
|
@ -33,6 +34,12 @@ public final class Utils {
|
||||||
return calendar.getTime();
|
return calendar.getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Date twoWeeksFromNow() {
|
||||||
|
GregorianCalendar calendar = new GregorianCalendar();
|
||||||
|
calendar.add(Calendar.DATE, 14);
|
||||||
|
return calendar.getTime();
|
||||||
|
}
|
||||||
|
|
||||||
public static User getCurrentUser() {
|
public static User getCurrentUser() {
|
||||||
Object user = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
Object user = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||||
if (user instanceof User) {
|
if (user instanceof User) {
|
||||||
|
@ -42,7 +49,18 @@ public final class Utils {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||||
|
private static final Random random = new SecureRandom();
|
||||||
|
|
||||||
|
public static String randomString(int length) {
|
||||||
|
StringBuilder id = new StringBuilder();
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
id.append(CHARACTERS.charAt(random.nextInt(CHARACTERS.length())));
|
||||||
|
}
|
||||||
|
return id.toString();
|
||||||
|
}
|
||||||
|
|
||||||
public static String randomId() {
|
public static String randomId() {
|
||||||
return UUID.randomUUID().toString().replace("-", "");
|
return randomString(32);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,5 +2,5 @@ package com.wbrawner.budgetserver.budget;
|
||||||
|
|
||||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||||
|
|
||||||
public interface BudgetRepository extends PagingAndSortingRepository<Budget, Long> {
|
public interface BudgetRepository extends PagingAndSortingRepository<Budget, String> {
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package com.wbrawner.budgetserver.config;
|
package com.wbrawner.budgetserver.config;
|
||||||
|
|
||||||
import com.wbrawner.budgetserver.passwordresetrequest.PasswordResetRequestRepository;
|
import com.wbrawner.budgetserver.passwordresetrequest.PasswordResetRequestRepository;
|
||||||
|
import com.wbrawner.budgetserver.session.UserSessionRepository;
|
||||||
import com.wbrawner.budgetserver.user.UserRepository;
|
import com.wbrawner.budgetserver.user.UserRepository;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
@ -11,6 +12,7 @@ import org.springframework.security.config.annotation.authentication.builders.Au
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
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.configuration.EnableWebSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||||
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.security.provisioning.JdbcUserDetailsManager;
|
import org.springframework.security.provisioning.JdbcUserDetailsManager;
|
||||||
|
@ -28,6 +30,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
private final Environment env;
|
private final Environment env;
|
||||||
private final DataSource datasource;
|
private final DataSource datasource;
|
||||||
|
private final UserSessionRepository userSessionRepository;
|
||||||
private final UserRepository userRepository;
|
private final UserRepository userRepository;
|
||||||
private final PasswordResetRequestRepository passwordResetRequestRepository;
|
private final PasswordResetRequestRepository passwordResetRequestRepository;
|
||||||
private final JdbcUserDetailsService userDetailsService;
|
private final JdbcUserDetailsService userDetailsService;
|
||||||
|
@ -35,12 +38,14 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
public SecurityConfig(Environment env,
|
public SecurityConfig(Environment env,
|
||||||
DataSource datasource,
|
DataSource datasource,
|
||||||
|
UserSessionRepository userSessionRepository,
|
||||||
UserRepository userRepository,
|
UserRepository userRepository,
|
||||||
PasswordResetRequestRepository passwordResetRequestRepository,
|
PasswordResetRequestRepository passwordResetRequestRepository,
|
||||||
JdbcUserDetailsService userDetailsService,
|
JdbcUserDetailsService userDetailsService,
|
||||||
Environment environment) {
|
Environment environment) {
|
||||||
this.env = env;
|
this.env = env;
|
||||||
this.datasource = datasource;
|
this.datasource = datasource;
|
||||||
|
this.userSessionRepository = userSessionRepository;
|
||||||
this.userRepository = userRepository;
|
this.userRepository = userRepository;
|
||||||
this.passwordResetRequestRepository = passwordResetRequestRepository;
|
this.passwordResetRequestRepository = passwordResetRequestRepository;
|
||||||
this.userDetailsService = userDetailsService;
|
this.userDetailsService = userDetailsService;
|
||||||
|
@ -56,7 +61,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public DaoAuthenticationProvider getAuthenticationProvider() {
|
public DaoAuthenticationProvider getAuthenticationProvider() {
|
||||||
var authProvider = new DaoAuthenticationProvider();
|
var authProvider = new TokenAuthenticationProvider(userSessionRepository, userRepository);
|
||||||
authProvider.setPasswordEncoder(getPasswordEncoder());
|
authProvider.setPasswordEncoder(getPasswordEncoder());
|
||||||
authProvider.setUserDetailsService(userDetailsService);
|
authProvider.setUserDetailsService(userDetailsService);
|
||||||
return authProvider;
|
return authProvider;
|
||||||
|
@ -81,6 +86,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
.authenticated()
|
.authenticated()
|
||||||
.and()
|
.and()
|
||||||
.httpBasic()
|
.httpBasic()
|
||||||
|
.authenticationEntryPoint(new SilentAuthenticationEntryPoint())
|
||||||
.and()
|
.and()
|
||||||
.cors()
|
.cors()
|
||||||
.configurationSource(request -> {
|
.configurationSource(request -> {
|
||||||
|
@ -104,7 +110,9 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
})
|
})
|
||||||
.and()
|
.and()
|
||||||
.csrf()
|
.csrf()
|
||||||
.disable();
|
.disable()
|
||||||
|
.addFilter(new TokenAuthenticationFilter(authenticationManager()))
|
||||||
|
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
package com.wbrawner.budgetserver.config;
|
||||||
|
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
public class SessionAuthenticationToken extends UsernamePasswordAuthenticationToken {
|
||||||
|
/**
|
||||||
|
* Creates a token with the supplied array of authorities.
|
||||||
|
*
|
||||||
|
* @param authorities the collection of <tt>GrantedAuthority</tt>s for the principal
|
||||||
|
* represented by this authentication object.
|
||||||
|
* @param credentials
|
||||||
|
* @param principal
|
||||||
|
*/
|
||||||
|
public SessionAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
|
||||||
|
super(principal, credentials, authorities);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.wbrawner.budgetserver.config;
|
||||||
|
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to avoid browser prompts for authentication
|
||||||
|
*/
|
||||||
|
public class SilentAuthenticationEntryPoint implements AuthenticationEntryPoint {
|
||||||
|
@Override
|
||||||
|
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
|
||||||
|
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package com.wbrawner.budgetserver.config;
|
||||||
|
|
||||||
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||||
|
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
public class TokenAuthenticationFilter extends BasicAuthenticationFilter {
|
||||||
|
|
||||||
|
public TokenAuthenticationFilter(AuthenticationManager authenticationManager) {
|
||||||
|
super(authenticationManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||||
|
var authHeader = request.getHeader("Authorization");
|
||||||
|
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var token = authHeader.substring(7);
|
||||||
|
var authentication = getAuthenticationManager().authenticate(new SessionAuthenticationToken(null, token, Collections.emptyList()));
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
package com.wbrawner.budgetserver.config;
|
||||||
|
|
||||||
|
import com.wbrawner.budgetserver.session.UserSessionRepository;
|
||||||
|
import com.wbrawner.budgetserver.user.UserRepository;
|
||||||
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
|
import org.springframework.security.authentication.InternalAuthenticationServiceException;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class TokenAuthenticationProvider extends DaoAuthenticationProvider {
|
||||||
|
private final UserSessionRepository userSessionRepository;
|
||||||
|
private final UserRepository userRepository;
|
||||||
|
|
||||||
|
public TokenAuthenticationProvider(UserSessionRepository userSessionRepository, UserRepository userRepository) {
|
||||||
|
this.userSessionRepository = userSessionRepository;
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
|
||||||
|
if (!(authentication instanceof SessionAuthenticationToken)) {
|
||||||
|
// Additional checks aren't needed since they've already been handled
|
||||||
|
super.additionalAuthenticationChecks(userDetails, authentication);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||||
|
if (authentication instanceof SessionAuthenticationToken) {
|
||||||
|
var session = userSessionRepository.findByToken((String) authentication.getCredentials());
|
||||||
|
if (session.isEmpty() || session.get().getExpiration().before(new Date())) {
|
||||||
|
throw new BadCredentialsException("Credentials expired");
|
||||||
|
}
|
||||||
|
var user = userRepository.findById(session.get().getUserId());
|
||||||
|
if (user.isEmpty()) {
|
||||||
|
throw new InternalAuthenticationServiceException("Failed to find user for token");
|
||||||
|
}
|
||||||
|
return new SessionAuthenticationToken(user.get(), authentication.getCredentials(), authentication.getAuthorities());
|
||||||
|
} else {
|
||||||
|
return super.authenticate(authentication);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package com.wbrawner.budgetserver.session;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import static com.wbrawner.budgetserver.Utils.*;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class Session {
|
||||||
|
@Id
|
||||||
|
private final String id = randomId();
|
||||||
|
private final String userId;
|
||||||
|
private final String token = randomString(255);
|
||||||
|
private Date expiration = twoWeeksFromNow();
|
||||||
|
|
||||||
|
public Session() {
|
||||||
|
this("");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Session(String userId) {
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserId() {
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getToken() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getExpiration() {
|
||||||
|
return expiration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpiration(Date expiration) {
|
||||||
|
this.expiration = expiration;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.wbrawner.budgetserver.session;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class SessionCleanupTask {
|
||||||
|
private final UserSessionRepository sessionRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public SessionCleanupTask(UserSessionRepository sessionRepository) {
|
||||||
|
this.sessionRepository = sessionRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Scheduled(cron = "0 0 * * * *")
|
||||||
|
public void cleanup() {
|
||||||
|
sessionRepository.deleteAllByExpirationBefore(new Date());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package com.wbrawner.budgetserver.session;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class SessionResponse {
|
||||||
|
private final String token;
|
||||||
|
private final String expiration;
|
||||||
|
|
||||||
|
public SessionResponse(Session session) {
|
||||||
|
this(session.getToken(), session.getExpiration());
|
||||||
|
}
|
||||||
|
|
||||||
|
public SessionResponse(String token, Date expiration) {
|
||||||
|
this.token = token;
|
||||||
|
this.expiration = expiration.toInstant().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getToken() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExpiration() {
|
||||||
|
return expiration;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.wbrawner.budgetserver.session;
|
||||||
|
|
||||||
|
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public interface UserSessionRepository extends PagingAndSortingRepository<Session, String> {
|
||||||
|
List<Session> findByUserId(String userId);
|
||||||
|
|
||||||
|
Optional<Session> findByToken(String token);
|
||||||
|
|
||||||
|
Optional<Session> findByUserIdAndToken(String userId, String token);
|
||||||
|
|
||||||
|
void deleteAllByExpirationBefore(Date expiration);
|
||||||
|
}
|
|
@ -1,10 +1,13 @@
|
||||||
package com.wbrawner.budgetserver.user;
|
package com.wbrawner.budgetserver.user;
|
||||||
|
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
|
||||||
import javax.persistence.*;
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Transient;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -31,6 +34,7 @@ public class User implements UserDetails {
|
||||||
this.email = email;
|
this.email = email;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
public String getId() {
|
public String getId() {
|
||||||
// This shouldn't ever need to be set manually, only through Hibernate
|
// This shouldn't ever need to be set manually, only through Hibernate
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
|
|
|
@ -4,6 +4,9 @@ import com.wbrawner.budgetserver.ErrorResponse;
|
||||||
import com.wbrawner.budgetserver.budget.BudgetRepository;
|
import com.wbrawner.budgetserver.budget.BudgetRepository;
|
||||||
import com.wbrawner.budgetserver.permission.UserPermissionRepository;
|
import com.wbrawner.budgetserver.permission.UserPermissionRepository;
|
||||||
import com.wbrawner.budgetserver.permission.UserPermissionResponse;
|
import com.wbrawner.budgetserver.permission.UserPermissionResponse;
|
||||||
|
import com.wbrawner.budgetserver.session.Session;
|
||||||
|
import com.wbrawner.budgetserver.session.SessionResponse;
|
||||||
|
import com.wbrawner.budgetserver.session.UserSessionRepository;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import io.swagger.annotations.Authorization;
|
import io.swagger.annotations.Authorization;
|
||||||
|
@ -20,6 +23,7 @@ import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.transaction.Transactional;
|
import javax.transaction.Transactional;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static com.wbrawner.budgetserver.Utils.getCurrentUser;
|
import static com.wbrawner.budgetserver.Utils.getCurrentUser;
|
||||||
|
@ -33,16 +37,19 @@ public class UserController {
|
||||||
private final UserRepository userRepository;
|
private final UserRepository userRepository;
|
||||||
private final PasswordEncoder passwordEncoder;
|
private final PasswordEncoder passwordEncoder;
|
||||||
private final UserPermissionRepository userPermissionsRepository;
|
private final UserPermissionRepository userPermissionsRepository;
|
||||||
|
private final UserSessionRepository userSessionRepository;
|
||||||
private final DaoAuthenticationProvider authenticationProvider;
|
private final DaoAuthenticationProvider authenticationProvider;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public UserController(BudgetRepository budgetRepository,
|
public UserController(BudgetRepository budgetRepository,
|
||||||
UserRepository userRepository,
|
UserRepository userRepository,
|
||||||
|
UserSessionRepository userSessionRepository,
|
||||||
PasswordEncoder passwordEncoder,
|
PasswordEncoder passwordEncoder,
|
||||||
UserPermissionRepository userPermissionsRepository,
|
UserPermissionRepository userPermissionsRepository,
|
||||||
DaoAuthenticationProvider authenticationProvider) {
|
DaoAuthenticationProvider authenticationProvider) {
|
||||||
this.budgetRepository = budgetRepository;
|
this.budgetRepository = budgetRepository;
|
||||||
this.userRepository = userRepository;
|
this.userRepository = userRepository;
|
||||||
|
this.userSessionRepository = userSessionRepository;
|
||||||
this.passwordEncoder = passwordEncoder;
|
this.passwordEncoder = passwordEncoder;
|
||||||
this.userPermissionsRepository = userPermissionsRepository;
|
this.userPermissionsRepository = userPermissionsRepository;
|
||||||
this.authenticationProvider = authenticationProvider;
|
this.authenticationProvider = authenticationProvider;
|
||||||
|
@ -51,7 +58,7 @@ public class UserController {
|
||||||
|
|
||||||
@GetMapping(path = "", produces = {MediaType.APPLICATION_JSON_VALUE})
|
@GetMapping(path = "", produces = {MediaType.APPLICATION_JSON_VALUE})
|
||||||
@ApiOperation(value = "getUsers", nickname = "getUsers", tags = {"Users"})
|
@ApiOperation(value = "getUsers", nickname = "getUsers", tags = {"Users"})
|
||||||
ResponseEntity<List<UserPermissionResponse>> getUsers(Long budgetId) {
|
ResponseEntity<List<UserPermissionResponse>> getUsers(String budgetId) {
|
||||||
var budget = budgetRepository.findById(budgetId).orElse(null);
|
var budget = budgetRepository.findById(budgetId).orElse(null);
|
||||||
if (budget == null) {
|
if (budget == null) {
|
||||||
return ResponseEntity.notFound().build();
|
return ResponseEntity.notFound().build();
|
||||||
|
@ -69,7 +76,7 @@ public class UserController {
|
||||||
|
|
||||||
@PostMapping(path = "/login", produces = {MediaType.APPLICATION_JSON_VALUE})
|
@PostMapping(path = "/login", produces = {MediaType.APPLICATION_JSON_VALUE})
|
||||||
@ApiOperation(value = "login", nickname = "login", tags = {"Users"})
|
@ApiOperation(value = "login", nickname = "login", tags = {"Users"})
|
||||||
ResponseEntity<UserResponse> login(@RequestBody LoginRequest request) {
|
ResponseEntity<SessionResponse> login(@RequestBody LoginRequest request) {
|
||||||
var authReq = new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword());
|
var authReq = new UsernamePasswordAuthenticationToken(request.getUsername(), request.getPassword());
|
||||||
Authentication auth;
|
Authentication auth;
|
||||||
try {
|
try {
|
||||||
|
@ -78,7 +85,9 @@ public class UserController {
|
||||||
return ResponseEntity.notFound().build();
|
return ResponseEntity.notFound().build();
|
||||||
}
|
}
|
||||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||||
return ResponseEntity.ok(new UserResponse(getCurrentUser()));
|
var user = Objects.requireNonNull(getCurrentUser());
|
||||||
|
var session = userSessionRepository.save(new Session(user.getId()));
|
||||||
|
return ResponseEntity.ok(new SessionResponse(session));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping(path = "/me", produces = {MediaType.APPLICATION_JSON_VALUE})
|
@GetMapping(path = "/me", produces = {MediaType.APPLICATION_JSON_VALUE})
|
||||||
|
|
Loading…
Reference in a new issue