Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of Register to Platform #35

Merged
merged 9 commits into from
Mar 22, 2023
14 changes: 10 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,18 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jooq</artifactId>
</dependency>
<!--

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
-->

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
Expand Down Expand Up @@ -88,13 +94,13 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
-->

<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
Expand Down
84 changes: 84 additions & 0 deletions src/main/java/com/ays/backend/config/SecurityConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.ays.backend.config;

import com.ays.backend.user.security.JwtAuthenticationEntryPoint;
import com.ays.backend.user.security.JwtAuthenticationFilter;
import com.ays.backend.user.security.JwtTokenProvider;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {

private final UserDetailsService userDetailsService;

private final JwtAuthenticationEntryPoint handler;

private final JwtTokenProvider jwtTokenProvider;

@Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter(jwtTokenProvider, userDetailsService);
}

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

@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}

@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("OPTIONS");
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}

@Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.cors()
.and()
.csrf().disable()
.exceptionHandling().authenticationEntryPoint(handler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeHttpRequests()
.requestMatchers(HttpMethod.GET, "/swagger-ui/**", "/v3/api-docs/**").permitAll()
.requestMatchers(HttpMethod.POST, "/api/v1/admin/register").permitAll()
.anyRequest().authenticated();

httpSecurity.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
return httpSecurity.build();
}
}
12 changes: 12 additions & 0 deletions src/main/java/com/ays/backend/mapper/BaseMapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.ays.backend.mapper;

import java.util.Collection;
import java.util.List;

public interface BaseMapper<S, T> {

T map(S source);

List<T> map(Collection<S> sources);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.ays.backend.mapper;

import com.ays.backend.user.controller.payload.request.AdminRegisterRequest;
import com.ays.backend.user.model.entities.User;
import org.mapstruct.Mapper;

@Mapper
public interface UserAdminRegisterRequestToUserEntityMapper extends BaseMapper<AdminRegisterRequest, User> {

}
2 changes: 2 additions & 0 deletions src/main/java/com/ays/backend/mapper/UserMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@


@Mapper(componentModel = "spring", nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
// TODO : Use BaseMapper
// extends BaseMapper<User, UserDTO>
public interface UserMapper {

User mapUserDTOtoUser(UserDTO userDTO);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.ays.backend.user.controller;

import com.ays.backend.user.controller.payload.request.AdminRegisterRequest;
import com.ays.backend.user.controller.payload.response.MessageResponse;
import com.ays.backend.user.security.JwtTokenProvider;
import com.ays.backend.user.service.AuthService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* Auth controller to perform authentication api operations.
*/
@RestController
@RequestMapping("/api/v1/admin")
@RequiredArgsConstructor
public class AuthController {

private final AuthService authService;

private final AuthenticationManager authenticationManager;

private final JwtTokenProvider jwtTokenProvider;


/**
* This endpoint allows admin to register to platform.
*
* @param registerRequest A AdminRegisterRequest object required to register to platform .
* @return A ResponseEntity containing a MessageResponse object with success message of the newly created admin and
* the HTTP status code (201 CREATED).
*/
@PostMapping("/register")
public ResponseEntity<MessageResponse> register(@RequestBody AdminRegisterRequest registerRequest) {

// TODO : return type registeredUser unused temporarily now, perhaps delete it later if it is not used.
var registeredUser = authService.register(registerRequest);

MessageResponse messageResponse = new MessageResponse("success");

return new ResponseEntity<>(messageResponse, HttpStatus.CREATED);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,7 @@ public class UserController {
*/
@PostMapping
public ResponseEntity<SignUpResponse> registerUser(@RequestBody @Valid SignUpRequest signUpRequest) {
if (Boolean.TRUE.equals(userService.existsByUsername(signUpRequest.getUsername()))) {
throw new UserAlreadyExistsException("Error: Username is already taken!");
}


var createdUser = userService.saveUser(signUpRequest);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.ays.backend.user.controller.payload.request;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class AdminRegisterRequest {

@NotBlank
private String username;

@NotBlank
private String password;

@NotNull
private Integer countryCode;

@NotNull
private Integer lineNumber;

@NotBlank
private String firstName;

@NotBlank
private String lastName;

@NotBlank
@Email
private String email;

@NotNull
private Long organizationId;

@NotNull
private Integer statusValue;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.ays.backend.user.controller.payload.response;

import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class AuthResponse {
String message;
String accessToken;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.ays.backend.user.exception;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(HttpStatus.NOT_FOUND)
public class OrganizationNotFoundException extends RuntimeException {

public OrganizationNotFoundException(String msg) {
super(msg);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.ays.backend.user.model.entities;

import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.Instant;

/**
* RefreshToken entity, which holds the information regarding the refresh token.
*/
@Entity
@Table(name = "refreshToken")
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class RefreshToken {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@OneToOne
@JoinColumn(name = "user_id", referencedColumnName = "id")
private User user;

@Column(nullable = false, unique = true)
private String token;

@Column(nullable = false)
private Instant expiryDate;
}
48 changes: 30 additions & 18 deletions src/main/java/com/ays/backend/user/model/entities/User.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,14 @@
package com.ays.backend.user.model.entities;

import java.time.LocalDateTime;

import com.ays.backend.user.controller.payload.request.AdminRegisterRequest;
import com.ays.backend.user.model.enums.UserRole;
import com.ays.backend.user.model.enums.UserStatus;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;
import jakarta.persistence.*;
import jakarta.validation.constraints.Email;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.*;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.time.LocalDateTime;

/**
* Users entity, which holds the information regarding the system user.
Expand Down Expand Up @@ -51,7 +42,7 @@ public class User extends BaseEntity {
private String password;

@OneToOne
@JoinColumn(name = "organization_id")
@JoinColumn(name = "organization_id", referencedColumnName = "id", insertable = false, updatable = false)
private Organization organization;

@Enumerated(EnumType.ORDINAL)
Expand All @@ -64,12 +55,33 @@ public class User extends BaseEntity {
private UserStatus status;

@Column(nullable = false)
private int countryCode;
private Integer countryCode;

@Column(nullable = false)
private int lineNumber;
private Integer lineNumber;

@Column
private LocalDateTime lastLoginDate;

@Column(name = "organization_id")
private Long organizationId;

public static User from(AdminRegisterRequest registerRequest, PasswordEncoder passwordEncoder) {

return User.builder()
.username(registerRequest.getUsername())
.password(passwordEncoder.encode(registerRequest.getPassword()))
.firstName(registerRequest.getFirstName())
.lastName(registerRequest.getLastName())
.userRole(UserRole.ROLE_ADMIN)
.countryCode(registerRequest.getCountryCode())
.lineNumber(registerRequest.getLineNumber())
.email(registerRequest.getEmail())
.lastLoginDate(LocalDateTime.now())
.organizationId(registerRequest.getOrganizationId())
.status(UserStatus.getById(registerRequest.getStatusValue()))
.build();

}

}
Loading