Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions cadastral/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,25 @@
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>

<!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt-api -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>

<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>

<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.5.5.Final</version>
</dependency>


</dependencies>
<dependencyManagement>
Expand All @@ -133,6 +152,11 @@
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.5.5.Final</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.bson.Document;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.util.List;
Expand Down Expand Up @@ -53,16 +54,32 @@ public void run(String... args) throws Exception {
if (userCount == 0) {
System.out.println("Usuários não encontrados, criando inicialização...");

Document roleAdmin = roleCollection.find(new Document("roleName", "ROLE_ADMINISTRATOR")).first();

if (roleAdmin == null) {
throw new IllegalStateException("Role 'ROLE_ADMINISTRATOR' não encontrada no banco!");
}

userCollection.insertMany(List.of(
new Document("_id", "admin-1")
.append("userName", dotenv.get("ADMIN1_USERNAME"))
.append("password", passwordEncoder.encode(dotenv.get("ADMIN1_PASSWORD"))) // Senha criptografada
.append("roles", UserType.ROLE_ADMINISTRATOR),
.append("password", passwordEncoder.encode(dotenv.get("ADMIN1_PASSWORD")))
.append("roles", List.of(roleAdmin)),

new Document("_id", "admin-2")
.append("userName", dotenv.get("ADMIN2_USERNAME"))
.append("password", passwordEncoder.encode(dotenv.get("ADMIN2_PASSWORD"))) // Senha criptografada
.append("roles", UserType.ROLE_ADMINISTRATOR)
.append("password", passwordEncoder.encode(dotenv.get("ADMIN2_PASSWORD")))
.append("roles", List.of(roleAdmin)),

new Document("_id", "admin-3")
.append("userName", dotenv.get("ADMIN3_USERNAME"))
.append("password", passwordEncoder.encode(dotenv.get("ADMIN3_PASSWORD")))
.append("roles", List.of(roleAdmin)),

new Document("_id", "admin-4")
.append("userName", dotenv.get("ADMIN4_USERNAME"))
.append("password", passwordEncoder.encode(dotenv.get("ADMIN4_PASSWORD")))
.append("roles", List.of(roleAdmin))
));

System.out.println("Usuários criados com sucesso!");
Expand Down
24 changes: 24 additions & 0 deletions cadastral/src/main/java/com/unipampa/crud/config/RabbitConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.unipampa.crud.config;

import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitConfig {

@Bean
public Jackson2JsonMessageConverter jackson2JsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}

@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory,
Jackson2JsonMessageConverter converter) {
RabbitTemplate template = new RabbitTemplate(connectionFactory);
template.setMessageConverter(converter);
return template;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.unipampa.crud.config.security;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

@Autowired
private JwtProvider jwtProvider;

@Autowired
private UserDetailsServiceImpl userDetailsService;

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String token = extractToken(request);
if (token != null && jwtProvider.validateToken(token)) {
String userId = jwtProvider.getSubjectFromToken(token);
logger.info("username extraído do token: " + userId);

UserDetails userDetails = userDetailsService.loadUserByUserId(userId);
logger.info("user details encontrado: " + userDetails);

UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());

SecurityContextHolder.getContext().setAuthentication(authentication);
}

filterChain.doFilter(request, response);

}

private String extractToken(HttpServletRequest request) {
String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
return authHeader.substring(7);
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.unipampa.crud.config.security;

import io.jsonwebtoken.*;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;

import java.util.Date;

@Log4j2
@Component
public class JwtProvider {

@Value( "${ead.auth.jwtSecret}")
private String jwtSecret;

@Value( "${ead.auth.jwtExpirationMs}")
private int jwtExpirationMs;

public String generateJwtToken(Authentication authentication) {
UserDatailsImpl userPrincipal = (UserDatailsImpl) authentication.getPrincipal();
return Jwts.builder()
.setSubject(userPrincipal.getUserId())
.setIssuedAt(new Date())
.setExpiration(new Date((new Date()).getTime() + jwtExpirationMs))
.signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, jwtSecret)
.compact();
}

public String getSubjectFromToken(String token) {
return Jwts.parser()
.setSigningKey(jwtSecret)
.parseClaimsJws(token)
.getBody()
.getSubject();
}

public boolean validateToken(String authToken) {
try {
Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken);
return true;

} catch (SignatureException e) {
log.error("Invalid JWT signature: {}", e.getMessage());
} catch (MalformedJwtException e) {
log.error("Invalid JWT token: {}", e.getMessage());
} catch (ExpiredJwtException e) {
log.error("JWT token is expired: {}", e.getMessage());
} catch (UnsupportedJwtException e) {
log.error("JWT token is unsupported: {}", e.getMessage());
} catch (IllegalArgumentException e) {
log.error("JWT claims string is empty: {}", e.getMessage());
}
return false;
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.unipampa.crud.config.security;

import jakarta.ws.rs.HttpMethod;
import org.springframework.beans.factory.annotation.Autowired;
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.Customizer;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
Expand All @@ -13,42 +13,30 @@
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;

@Configuration
@EnableMethodSecurity
public class SecurityConfig {

private static final String HOST = "HOST";
private static final String ADMIN = "ADMINISTRATOR";
private static final String GUEST = "GUEST";
@Autowired
private UserDetailsServiceImpl userDetailsService;

private static final String[] PUBLIC_MATCHERS = {
"/users/**"
};
@Autowired
private JwtAuthenticationFilter jwtAuthenticationFilter;

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth -> auth
.requestMatchers(HttpMethod.POST, PUBLIC_MATCHERS).permitAll()
.requestMatchers("/accommodations/images/**").permitAll()
.requestMatchers(HttpMethod.POST, "/accommodations/**").hasAnyRole(HOST, ADMIN)
.requestMatchers(HttpMethod.GET, "/accommodations/**").hasAnyRole(HOST, GUEST, ADMIN)
.requestMatchers(HttpMethod.GET, "/accommodations/{id}").hasAnyRole(HOST, GUEST, ADMIN)
.requestMatchers(HttpMethod.PUT, "/accommodations/{id}").hasAnyRole(HOST, ADMIN)
.requestMatchers(HttpMethod.DELETE, "/accommodations/{id}").hasAnyRole(HOST, ADMIN)

.requestMatchers(HttpMethod.GET, "/users").hasRole(ADMIN)
.requestMatchers(HttpMethod.GET, "/users/email/**").hasAnyRole(ADMIN, HOST, GUEST)
.requestMatchers(HttpMethod.GET, "/users/{id}").hasAnyRole(ADMIN, HOST, GUEST)
.requestMatchers(HttpMethod.PUT, "/users/{id}").hasAnyRole(ADMIN, HOST, GUEST)
.requestMatchers(HttpMethod.DELETE, "/users/{id}").hasAnyRole(ADMIN, HOST, GUEST)

http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(auth -> auth
.requestMatchers(HttpMethod.POST, "/users/**", "/auth/**").permitAll()
.requestMatchers(HttpMethod.GET, "/accommodations", "/accommodations/**", "/images/**").permitAll()
.anyRequest().authenticated()
)
.httpBasic(Customizer.withDefaults())
.csrf(AbstractHttpConfigurer::disable);
.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.httpBasic(Customizer.withDefaults());

return http.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class UserDatailsImpl implements UserDetails {

public static UserDatailsImpl build(User user) {
List<GrantedAuthority> authorities = user.getRoles().stream()
.map(role -> new SimpleGrantedAuthority(role.getAuthority()))
.map(role -> new SimpleGrantedAuthority(role.getRoleName().name()))
.collect(Collectors.toList());

return new UserDatailsImpl (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.unipampa.crud.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
Expand All @@ -10,19 +11,26 @@
@Service
public class UserDetailsServiceImpl implements UserDetailsService {

public static final String USER_NOT_FOUND = "Usuário não encontrado para o nome de usuário: ";
public static final String USER_NOT_FOUND = "Usuário não encontrado para o id de usuário: ";

@Autowired
private UserRepository userRepository;

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
try {
var user = userRepository.findByUserName(username)
.orElseThrow(() -> new UsernameNotFoundException(USER_NOT_FOUND + username));
return UserDatailsImpl.build(user);
var user = userRepository.findByUserName(username);
var opt = user.orElseThrow(() -> new UsernameNotFoundException(USER_NOT_FOUND + username));
return UserDatailsImpl.build(opt);
} catch (Exception e) {
throw new UsernameNotFoundException("Erro de conectividade ou ao carregar os dados do usuário: " + username, e);
}
}

public UserDetails loadUserByUserId(String userId) throws AuthenticationCredentialsNotFoundException {
var user = userRepository.findById(userId);
var userModel = user.orElseThrow(() -> new AuthenticationCredentialsNotFoundException(USER_NOT_FOUND + userId));
return UserDatailsImpl.build(userModel);

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.unipampa.crud.dto;

import lombok.Data;

import java.math.BigDecimal;

@Data
public class AccommodationMessageDTO {
private BigDecimal price;
private int maxOccupancy;
}
15 changes: 15 additions & 0 deletions cadastral/src/main/java/com/unipampa/crud/dto/JwtDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.unipampa.crud.dto;

import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.RequiredArgsConstructor;

@Data
@RequiredArgsConstructor
public class JwtDTO {

@NotNull
private final String token;

private final String type = "Bearer";
}
13 changes: 13 additions & 0 deletions cadastral/src/main/java/com/unipampa/crud/dto/LoginDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.unipampa.crud.dto;

import jakarta.validation.constraints.NotBlank;

public record LoginDTO(

@NotBlank
String username,

@NotBlank
String password

) {}
2 changes: 2 additions & 0 deletions cadastral/src/main/java/com/unipampa/crud/entities/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class User implements Serializable {

@Id
private String id;
@Field("userName")
private String userName;
private String password;
private String cpf;
Expand All @@ -46,4 +47,5 @@ public class User implements Serializable {
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'")
private LocalDateTime lastUpdateDate;


}
Loading