Skip to content

Commit

Permalink
Merge pull request #50 from Arquisoft/feat/api/deployment-ready
Browse files Browse the repository at this point in the history
feat: deployment Github actions, docker compose for Spring API and code cleaning
  • Loading branch information
UO283615 authored Feb 20, 2024
2 parents 0851d7e + ba7f09f commit 42e1499
Show file tree
Hide file tree
Showing 11 changed files with 111 additions and 211 deletions.
84 changes: 18 additions & 66 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,84 +39,36 @@ jobs:
- run: npm --prefix webapp install
- run: npm --prefix webapp run build
- run: npm --prefix webapp run test:e2e
docker-push-webapp:
name: Push webapp Docker Image to GitHub Packages
docker-push-api:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
needs: [e2e-tests]
needs: [ e2e-tests ]
steps:
- uses: actions/checkout@v4
- name: Publish to Registry
uses: elgohr/Publish-Docker-Github-Action@v5
env:
API_URI: http://${{ secrets.DEPLOY_HOST }}:8000
with:
name: arquisoft/wiq_en2b/webapp
- uses: actions/checkout@v4
- name: Publish to Registry
uses: elgohr/Publish-Docker-Github-Action@v5
env:
API_URI: http://${{ secrets.DEPLOY_HOST }}:8080
DATABASE_USER: ${{ secrets.DATABASE_USER }}
DATABASE_PASSWORD: ${{ secrets.DATABASE_PASSWORD }}
JWT_SECRET: ${{ secrets.JWT_SECRET }}
with:
name: arquisoft/wiq_en2b/api
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
registry: ghcr.io
workdir: webapp
workdir: api
buildargs: API_URI
docker-push-authservice:
name: Push auth service Docker Image to GitHub Packages
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
needs: [e2e-tests]
steps:
- uses: actions/checkout@v4
- name: Publish to Registry
uses: elgohr/Publish-Docker-Github-Action@v5
with:
name: arquisoft/wiq_en2b/authservice
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
registry: ghcr.io
workdir: users/authservice
docker-push-userservice:
name: Push user service Docker Image to GitHub Packages
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
needs: [e2e-tests]
steps:
- uses: actions/checkout@v4
- name: Publish to Registry
uses: elgohr/Publish-Docker-Github-Action@v5
with:
name: arquisoft/wiq_en2b/userservice
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
registry: ghcr.io
workdir: users/userservice
docker-push-gatewayservice:
name: Push gateway service Docker Image to GitHub Packages
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
needs: [e2e-tests]
steps:
- uses: actions/checkout@v4
- name: Publish to Registry
uses: elgohr/Publish-Docker-Github-Action@v5
with:
name: arquisoft/wiq_en2b/gatewayservice
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
registry: ghcr.io
workdir: gatewayservice
deploy:
name: Deploy over SSH
runs-on: ubuntu-latest
needs: [docker-push-userservice,docker-push-authservice,docker-push-gatewayservice,docker-push-webapp]
needs: [docker-push-api]
steps:
- name: Deploy over SSH
uses: fifsky/ssh-action@master
env:
DATABASE_USER: ${{ secrets.DATABASE_USER }}
DATABASE_PASSWORD: ${{ secrets.DATABASE_PASSWORD }}
JWT_SECRET: ${{ secrets.JWT_SECRET }}
with:
host: ${{ secrets.DEPLOY_HOST }}
user: ${{ secrets.DEPLOY_USER }}
Expand Down
23 changes: 23 additions & 0 deletions api/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
FROM maven:3.8.1-openjdk-17 AS build
# Compile api
WORKDIR /api
COPY . /api
WORKDIR /api
RUN mvn install
RUN mvn clean package

FROM amazoncorretto:17 AS runtime
# Copy the compiled jar file from the build stage
ARG DATABASE_USER
ARG DATABASE_PASSWORD
ARG JWT_SECRET

# Set environment variables
ENV DATABASE_URL jdbc:postgresql://WIQ_DB:5432/wiq
ENV DATABASE_USER $DATABASE_USER
ENV DATABASE_PASSWORD $DATABASE_PASSWORD
ENV JWT_SECRET $JWT_SECRET
COPY --from=build /api/target/quiz-api-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-jar","app.jar"]

EXPOSE 8080
7 changes: 3 additions & 4 deletions api/src/main/java/lab/en2b/quizapi/auth/AuthController.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,17 @@
import lab.en2b.quizapi.auth.dtos.LoginDto;
import lab.en2b.quizapi.auth.dtos.RefreshTokenDto;
import lab.en2b.quizapi.auth.dtos.RegisterDto;
import org.springframework.beans.factory.annotation.Autowired;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
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;
@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor
public class AuthController {

@Autowired
private AuthService authService;
private final AuthService authService;

@PostMapping("/register")
public ResponseEntity<?> registerUser(@Valid @RequestBody RegisterDto registerRequest){
Expand Down
11 changes: 11 additions & 0 deletions api/src/main/java/lab/en2b/quizapi/auth/AuthService.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,22 @@ public ResponseEntity<JwtResponseDto> login(LoginDto loginRequest){
);
}

/**
* Registers a user. Throws an 400 unauthorized exception otherwise
* @param registerRequest the request containing the register info
* @return a response containing a message
*/
public ResponseEntity<?> register(RegisterDto registerRequest) {
userService.createUser(registerRequest,Set.of("user"));
return ResponseEntity.ok("User registered successfully!");
}

/**
* Refreshes the jwt token. Throws an 404 unauthorized exception if the refresh token is not in the database or
* an 400 unauthorized exception if the refresh token is not valid
* @param refreshTokenRequest the request containing the refresh token
* @return a response containing a fresh jwt token and a refresh token
*/
public ResponseEntity<?> refreshToken(RefreshTokenDto refreshTokenRequest) {
User user = userService.findByRefreshToken(refreshTokenRequest.getRefreshToken()).orElseThrow(() -> new TokenRefreshException(
"Refresh token is not in database!"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import lab.en2b.quizapi.auth.jwt.JwtAuthFilter;
import lab.en2b.quizapi.commons.user.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
Expand All @@ -26,21 +25,18 @@
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
@Autowired
public UserService userService;
@Bean
public JwtAuthFilter authenticationJwtTokenFilter() {
return new JwtAuthFilter();
}

public final UserService userService;
public final JwtAuthFilter authenticationJwtTokenFilter;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
// Configure CORS settings here
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
Expand All @@ -64,7 +60,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http, Authentication
.anyRequest().authenticated())
.csrf(AbstractHttpConfigurer::disable)
.authenticationManager(authenticationManager)
.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(authenticationJwtTokenFilter, UsernamePasswordAuthenticationFilter.class)
.build();
//TODO: add exception handling
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ public static UserDetailsImpl build(User user) {
}
return new UserDetailsImpl(user.getId(),user.getUsername() , user.getEmail(), user.getPassword(), authorities);
}

@Override
public boolean isAccountNonExpired() {
return true;
Expand All @@ -48,6 +47,11 @@ public boolean isCredentialsNonExpired() {
public boolean isEnabled() {
return true;
}
public List<String> getStringRoles() {
return getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toList());
}
@Override
public boolean equals(Object o) {
if (this == o)
Expand All @@ -57,10 +61,4 @@ public boolean equals(Object o) {
UserDetailsImpl user = (UserDetailsImpl) o;
return Objects.equals(id, user.id);
}

public List<String> getStringRoles() {
return getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
package lab.en2b.quizapi.auth.dtos;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class RefreshTokenResponseDto {

private String token;
@JsonProperty("refresh_token")
private String refreshToken;

public RefreshTokenResponseDto(String accessToken, String refreshToken) {
this.token = accessToken;
this.refreshToken = refreshToken;
}

}
19 changes: 10 additions & 9 deletions api/src/main/java/lab/en2b/quizapi/auth/jwt/JwtAuthFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import jakarta.servlet.http.HttpServletResponse;
import lab.en2b.quizapi.commons.user.UserService;
import lombok.NonNull;
import org.springframework.beans.factory.annotation.Autowired;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
Expand All @@ -16,28 +16,29 @@

import java.io.IOException;
@Component
@RequiredArgsConstructor
public class JwtAuthFilter extends OncePerRequestFilter {

@Autowired
private JwtUtils jwtUtils;

@Autowired
private UserService userDetailsService;
private final JwtUtils jwtUtils;
private final UserService userDetailsService;

@Override
protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response,
@NonNull FilterChain filterChain) throws ServletException, IOException {
String token = parseJwt(request);
String email = null;

if(token != null){
email = jwtUtils.getSubjectFromJwtToken(token);
}

if ( email != null && SecurityContextHolder.getContext().getAuthentication() == null && isValidJwt(token)) {
UserDetails userDetails = userDetailsService.loadUserByUsername(email);
// this invokes UsernamePasswordAuthenticationToken, although it uses email as subject not username
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(userDetails,
null, userDetails.getAuthorities());
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
userDetails,
null,
userDetails.getAuthorities()
);
authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authToken);
}
Expand Down
24 changes: 11 additions & 13 deletions api/src/main/java/lab/en2b/quizapi/auth/jwt/JwtUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ public class JwtUtils {
@Value("${JWT_EXPIRATION_MS}")
private Long JWT_EXPIRATION_MS;


public String generateJwtTokenUserPassword(Authentication authentication) {
UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal();

Expand Down Expand Up @@ -52,13 +51,6 @@ public boolean validateJwtToken(String authToken) {
}
return false;
}
private Claims extractAllClaims(String token){
return Jwts.parser()
.verifyWith(getSignInKey())
.build()
.parseSignedClaims(token)
.getPayload();
}
public <T> T extractClaim(String token, Function<Claims,T> claimsResolver){
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
Expand All @@ -70,11 +62,6 @@ public String getSubjectFromJwtToken(String token) {
throw new IllegalArgumentException();
}
}
private SecretKey getSignInKey(){
byte[] keyBytes = Decoders.BASE64.decode(JWT_SECRET);
return Keys.hmacShaKeyFor(keyBytes);
}

public String generateTokenFromEmail(String email) {
return Jwts.builder()
.subject(email)
Expand All @@ -83,4 +70,15 @@ public String generateTokenFromEmail(String email) {
.signWith(getSignInKey())
.compact();
}
private SecretKey getSignInKey(){
byte[] keyBytes = Decoders.BASE64.decode(JWT_SECRET);
return Keys.hmacShaKeyFor(keyBytes);
}
private Claims extractAllClaims(String token){
return Jwts.parser()
.verifyWith(getSignInKey())
.build()
.parseSignedClaims(token)
.getPayload();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,4 @@
@SpringBootTest
class QuizApiApplicationTests {

@Test
void contextLoads() {
}

}
Loading

0 comments on commit 42e1499

Please sign in to comment.