diff --git a/pom.xml b/pom.xml index a690489..a2207ca 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ - + 4.0.0 @@ -29,11 +29,11 @@ org.springframework.boot spring-boot-starter - - - org.springframework.boot - spring-boot-starter-validation - + + + org.springframework.boot + spring-boot-starter-validation + org.springframework.boot spring-boot-starter-web @@ -62,6 +62,11 @@ provided + + org.springframework.boot + spring-boot-starter-security + + org.postgresql @@ -133,7 +138,26 @@ org.springdoc springdoc-openapi-starter-webmvc-ui - 2.5.0 + 2.2.0 + + + + + io.jsonwebtoken + jjwt-api + 0.11.5 + + + io.jsonwebtoken + jjwt-impl + 0.11.5 + runtime + + + io.jsonwebtoken + jjwt-jackson + 0.11.5 + runtime @@ -172,8 +196,8 @@ org.springframework.boot spring-boot-maven-plugin - - + + BBPS diff --git a/src/main/java/com/billpaymentservice/bbps/config/CustomUserDetailsService.java b/src/main/java/com/billpaymentservice/bbps/config/CustomUserDetailsService.java new file mode 100644 index 0000000..fb26179 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/config/CustomUserDetailsService.java @@ -0,0 +1,37 @@ +package com.billpaymentservice.bbps.config; + +import java.util.ArrayList; +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +import com.billpaymentservice.bbps.entites.UsersDetails; +import com.billpaymentservice.bbps.repository.UsersDetailsRepository; + +@Service +public class CustomUserDetailsService implements UserDetailsService { + + @Autowired + private UsersDetailsRepository userRepo; + + @Override + public UserDetails loadUserByUsername(String userMobNo) throws UsernameNotFoundException { + + String normalizedEmail = userMobNo; + + Optional adminOptional = userRepo.findByUserMobNo(normalizedEmail); + + if (adminOptional.isPresent()) { + UsersDetails user = adminOptional.get(); + return new User(user.getUserEmailId(), user.getUserMobNo(), new ArrayList<>()); + } else { + throw new UsernameNotFoundException("User not found with MobNo: " + userMobNo); + } + } + +} diff --git a/src/main/java/com/billpaymentservice/bbps/config/JwtAuthenticationEntryPoint.java b/src/main/java/com/billpaymentservice/bbps/config/JwtAuthenticationEntryPoint.java new file mode 100644 index 0000000..82a3c80 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/config/JwtAuthenticationEntryPoint.java @@ -0,0 +1,22 @@ +package com.billpaymentservice.bbps.config; + +import java.io.IOException; + +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +@Component +public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, + AuthenticationException authException) throws IOException, ServletException { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Access denied"); + + } +} diff --git a/src/main/java/com/billpaymentservice/bbps/config/JwtFilter.java b/src/main/java/com/billpaymentservice/bbps/config/JwtFilter.java new file mode 100644 index 0000000..fa06986 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/config/JwtFilter.java @@ -0,0 +1,72 @@ +package com.billpaymentservice.bbps.config; + +import java.io.IOException; + +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.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.MalformedJwtException; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +@Component +public class JwtFilter extends OncePerRequestFilter { + + @Autowired + private JwtUtil jwtUtil; + + @Autowired + private CustomUserDetailsService userDetailsService; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + + final String authorizationHeader = request.getHeader("Authentication"); + + String email = null; + String jwt = null; + + if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { + jwt = authorizationHeader.substring(7); + try { + email = jwtUtil.extractUsername(jwt); + } catch (IllegalArgumentException e) { + System.out.println("unable to get jwt tokken"); + } catch (ExpiredJwtException e) { + System.out.println("Jwt Exception jwt tokken"); + } catch (MalformedJwtException e) { + System.out.println("invelid jwt token"); + } + } + + if (email != null && SecurityContextHolder.getContext().getAuthentication() == null) { + + UserDetails userDetails = this.userDetailsService.loadUserByUsername(email); + + + if (jwtUtil.validateToken(jwt, userDetails)) { + + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + userDetails, null, userDetails.getAuthorities()); + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + SecurityContextHolder.getContext().setAuthentication(authentication); + + } else { + System.out.println("JWT Filter: Token validation failed for user - " + email); + + } + } + + filterChain.doFilter(request, response); + + } + +} diff --git a/src/main/java/com/billpaymentservice/bbps/config/JwtUtil.java b/src/main/java/com/billpaymentservice/bbps/config/JwtUtil.java new file mode 100644 index 0000000..1111b3e --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/config/JwtUtil.java @@ -0,0 +1,102 @@ +package com.billpaymentservice.bbps.config; + +import java.security.Key; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Service; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; + +@Service +public class JwtUtil { + + @Value("${jwt.secret}") + private String secret; + + private Key getSigningKey() { + byte[] keyBytes = Decoders.BASE64.decode(secret); + return Keys.hmacShaKeyFor(keyBytes); + } + + // Access Token - 2 Hours + private final long jwtExpirationInMs = 1000 * 60 * 60 * 2; // 2 hours + + // Refresh Token - 7 Days + private final long refreshExpirationDateInMs = 1000L * 60 * 60 * 24 * 7; // 7 days + + private final Map tokenBlacklist = new HashMap<>(); + + public String doGenerateRefreshToken(Map claims, String subject) { + return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis())) + .setExpiration(new Date(System.currentTimeMillis() + refreshExpirationDateInMs)) + .signWith(getSigningKey(), SignatureAlgorithm.HS512).compact(); + } + + public String extractUsername(String token) { + return extractClaim(token, Claims::getSubject); + } + + public Date extractExpiration(String token) { + return extractClaim(token, Claims::getExpiration); + } + + public T extractClaim(String token, Function claimsResolver) { + final Claims claims = extractAllClaims(token); + return claimsResolver.apply(claims); + } + + private Claims extractAllClaims(String token) { + return Jwts.parserBuilder().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody(); + } + + private Boolean isTokenExpired(String token) { + return extractExpiration(token).before(new Date()); + } + + public String generateToken(String username, String mid) { + Map claims = new HashMap<>(); + claims.put("mid", mid); + claims.put("expiryTime", new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10).toString()); + return createToken(claims, username.toUpperCase()); + } + + private String createToken(Map claims, String subject) { + return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis())) + .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) + .signWith(getSigningKey(), SignatureAlgorithm.HS512).compact(); + } + + private String createToken1(String subject) { + return Jwts.builder().setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis())) + .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) + .signWith(getSigningKey(), SignatureAlgorithm.HS512).compact(); + } + + public Boolean validateToken(String token, UserDetails userDetails) { + final String username = extractUsername(token); + return true; + } + + public void invalidateToken(String token) { + tokenBlacklist.put(token, new Date()); + } + + public boolean isTokenBlacklisted(String token) { + Date invalidationTime = tokenBlacklist.get(token); + return invalidationTime != null && invalidationTime.before(new Date()); + } + + public String generateToken(String mobileNo) { + return createToken1(mobileNo); + } + +} diff --git a/src/main/java/com/billpaymentservice/bbps/config/SecurityConfig.java b/src/main/java/com/billpaymentservice/bbps/config/SecurityConfig.java index ebe19d9..891013d 100644 --- a/src/main/java/com/billpaymentservice/bbps/config/SecurityConfig.java +++ b/src/main/java/com/billpaymentservice/bbps/config/SecurityConfig.java @@ -2,16 +2,52 @@ package com.billpaymentservice.bbps.config; import java.util.Arrays; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +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.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; @Configuration +@EnableWebSecurity public class SecurityConfig { + @Autowired + private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; + + @Autowired + private JwtFilter jwtFilter; + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + + http.csrf(csrf -> csrf.disable()).cors(cors -> cors.configurationSource(corsConfigurationSource())) + .authorizeHttpRequests(auth -> auth + .requestMatchers("/masterData/**", + "/v3/api-docs/**", + "/swagger-ui/**", + "/swagger-ui.html", + "/swagger-resources/**", + "/webjars/**", + "/error") + .permitAll().requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() // <-- Correct way + .anyRequest().authenticated()) + .exceptionHandling(ex -> ex.authenticationEntryPoint(jwtAuthenticationEntryPoint)) + .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); + + http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class); + + return http.build(); + } + @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration config = new CorsConfiguration(); diff --git a/src/main/java/com/billpaymentservice/bbps/controller/MasterDataController.java b/src/main/java/com/billpaymentservice/bbps/controller/MasterDataController.java index 8f94d77..0d011eb 100644 --- a/src/main/java/com/billpaymentservice/bbps/controller/MasterDataController.java +++ b/src/main/java/com/billpaymentservice/bbps/controller/MasterDataController.java @@ -16,9 +16,11 @@ import com.billpaymentservice.bbps.dto.request.BillerDetailRequest; import com.billpaymentservice.bbps.dto.request.ContactMasterRequest; import com.billpaymentservice.bbps.dto.request.CustomParamRequest; import com.billpaymentservice.bbps.dto.request.DispositionRequest; +import com.billpaymentservice.bbps.dto.request.LoginRequest; import com.billpaymentservice.bbps.dto.request.MasterCategoryRequest; import com.billpaymentservice.bbps.dto.request.MasterRequest; import com.billpaymentservice.bbps.dto.request.PlanRequest; +import com.billpaymentservice.bbps.dto.response.AuthResponse; import com.billpaymentservice.bbps.service.MasterDataService; import jakarta.validation.Valid; @@ -146,4 +148,14 @@ public class MasterDataController { return ResponseEntity.ok(masterDataService.fetchPlanByCategories(requestModel)); } + @PostMapping("/loginWithoutDecryption") + public ResponseEntity login(@RequestBody LoginRequest loginRequest) { + try { + AuthResponse authResponse = masterDataService.authenticateUser(loginRequest); + return ResponseEntity.ok(authResponse); + } catch (Exception e) { + return ResponseEntity.status(500).body(AuthResponse.builder().status("Unauthorized") + .message("An unexpected error occurred").statusCode(500).build()); + } + } } diff --git a/src/main/java/com/billpaymentservice/bbps/dto/UserDetailsDTO.java b/src/main/java/com/billpaymentservice/bbps/dto/UserDetailsDTO.java new file mode 100644 index 0000000..46575e1 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/dto/UserDetailsDTO.java @@ -0,0 +1,23 @@ +package com.billpaymentservice.bbps.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class UserDetailsDTO { + + private Long id; + + private String userEmailId; + + private String userMobNo; + + private String userName; + + private String userAge; +} diff --git a/src/main/java/com/billpaymentservice/bbps/dto/request/ComplaintRequestDTO.java b/src/main/java/com/billpaymentservice/bbps/dto/request/ComplaintRequestDTO.java index ed90f62..ee5b04e 100644 --- a/src/main/java/com/billpaymentservice/bbps/dto/request/ComplaintRequestDTO.java +++ b/src/main/java/com/billpaymentservice/bbps/dto/request/ComplaintRequestDTO.java @@ -11,7 +11,5 @@ public class ComplaintRequestDTO extends BaseClass { private String ticketDisposition; // Complaint disposition private String ticketDispositionCode; // Type of complaint private String txnId; // Transaction ID (optional) - private String billerId; // Client Req ID (optional); - private String billerName; - + } diff --git a/src/main/java/com/billpaymentservice/bbps/dto/request/LoginRequest.java b/src/main/java/com/billpaymentservice/bbps/dto/request/LoginRequest.java new file mode 100644 index 0000000..4023a6e --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/dto/request/LoginRequest.java @@ -0,0 +1,18 @@ +package com.billpaymentservice.bbps.dto.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; +import lombok.Data; +import lombok.Getter; +import lombok.Setter; + +@Data +@Getter +@Setter +public class LoginRequest { + + @NotBlank(message = "Mobile number is required") + @Pattern(regexp = "^[6-9]\\d{9}$", message = "Invalid mobile number. It must be 10 digits and start with 6, 7, 8, or 9.") + private String mobileNumber; + +} diff --git a/src/main/java/com/billpaymentservice/bbps/dto/response/AuthResponse.java b/src/main/java/com/billpaymentservice/bbps/dto/response/AuthResponse.java new file mode 100644 index 0000000..f508f46 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/dto/response/AuthResponse.java @@ -0,0 +1,43 @@ +package com.billpaymentservice.bbps.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AuthResponse { + + private String token; + + private String status; + + private String message; + + private int statusCode; + + private Object data; + + private String anotherData; + + // Constructor + public AuthResponse(String status, String message, int statusCode, String token) { + + this.status = status; + this.message = message; + this.statusCode = statusCode; + this.token = token; + } + + public AuthResponse(String token, String status, String message, int statusCode, Object data) { + this.token = token; + this.status = status; + this.message = message; + this.statusCode = statusCode; + this.data = data; + } + +} diff --git a/src/main/java/com/billpaymentservice/bbps/entites/UsersDetails.java b/src/main/java/com/billpaymentservice/bbps/entites/UsersDetails.java new file mode 100644 index 0000000..96b9e50 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/entites/UsersDetails.java @@ -0,0 +1,38 @@ +package com.billpaymentservice.bbps.entites; + +import com.billpaymentservice.bbps.audit.Auditable; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "user_details") +public class UsersDetails extends Auditable { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Column(name = "user_email_id") + private String userEmailId; + + @Column(name = "user_mob_no") + private String userMobNo; + + @Column(name = "user_name") + private String userName; + + @Column(name = "user_age") + private String userAge; + +} diff --git a/src/main/java/com/billpaymentservice/bbps/repository/UsersDetailsRepository.java b/src/main/java/com/billpaymentservice/bbps/repository/UsersDetailsRepository.java new file mode 100644 index 0000000..2f6a983 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/repository/UsersDetailsRepository.java @@ -0,0 +1,15 @@ +package com.billpaymentservice.bbps.repository; + +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import com.billpaymentservice.bbps.entites.UsersDetails; + +@Repository +public interface UsersDetailsRepository extends JpaRepository { + + Optional findByUserMobNo(String userMobNo); + +} diff --git a/src/main/java/com/billpaymentservice/bbps/service/MasterDataService.java b/src/main/java/com/billpaymentservice/bbps/service/MasterDataService.java index 19da574..74660e7 100644 --- a/src/main/java/com/billpaymentservice/bbps/service/MasterDataService.java +++ b/src/main/java/com/billpaymentservice/bbps/service/MasterDataService.java @@ -5,9 +5,11 @@ import com.billpaymentservice.bbps.dto.request.BillerDetailRequest; import com.billpaymentservice.bbps.dto.request.ContactMasterRequest; import com.billpaymentservice.bbps.dto.request.CustomParamRequest; import com.billpaymentservice.bbps.dto.request.DispositionRequest; +import com.billpaymentservice.bbps.dto.request.LoginRequest; import com.billpaymentservice.bbps.dto.request.MasterCategoryRequest; import com.billpaymentservice.bbps.dto.request.MasterRequest; import com.billpaymentservice.bbps.dto.request.PlanRequest; +import com.billpaymentservice.bbps.dto.response.AuthResponse; public interface MasterDataService { @@ -35,4 +37,6 @@ public interface MasterDataService { public ResponseModel getTicketDispositions(DispositionRequest dispositionDetailRequest); + public AuthResponse authenticateUser(LoginRequest loginRequest); + } diff --git a/src/main/java/com/billpaymentservice/bbps/serviceImpl/ComplainServiceImpl.java b/src/main/java/com/billpaymentservice/bbps/serviceImpl/ComplainServiceImpl.java index 4b69980..5ae05b2 100644 --- a/src/main/java/com/billpaymentservice/bbps/serviceImpl/ComplainServiceImpl.java +++ b/src/main/java/com/billpaymentservice/bbps/serviceImpl/ComplainServiceImpl.java @@ -3,6 +3,7 @@ package com.billpaymentservice.bbps.serviceImpl; import java.util.List; import java.util.Map; +import java.util.Optional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,10 +32,12 @@ import com.billpaymentservice.bbps.entites.BharatConnectMaster; import com.billpaymentservice.bbps.entites.ComplaintStatusOptionsMaster; import com.billpaymentservice.bbps.entites.InboundTraceLog; import com.billpaymentservice.bbps.entites.OutboundTraceLog; +import com.billpaymentservice.bbps.entites.TransactionMaster; import com.billpaymentservice.bbps.exception.CustomException; import com.billpaymentservice.bbps.repository.BharatConnectMasterRepository; import com.billpaymentservice.bbps.repository.ComplainRepository; import com.billpaymentservice.bbps.repository.ComplaintOptionsStatusMasterRepository; +import com.billpaymentservice.bbps.repository.TransactionMasterRepository; import com.billpaymentservice.bbps.service.ComplainService; import com.billpaymentservice.bbps.util.BBPSConstant; import com.billpaymentservice.bbps.util.BillerMapperHelper; @@ -61,6 +64,7 @@ public class ComplainServiceImpl implements ComplainService { private final BillerMapperHelper mapperHelper; private final ComplainRepository complainRepository; private final ComplaintOptionsStatusMasterRepository complaintStatusMasterRepository; + private final TransactionMasterRepository transactionMasterRepository; // moved to class-level private final ObjectMapper objectMapper; @@ -69,7 +73,8 @@ public class ComplainServiceImpl implements ComplainService { public ComplainServiceImpl(RestClient restClient, HttpService httpService, Helper helper, BharatConnectMasterRepository beneficiaryDetailsRepository, BillerMapperHelper mapperHelper, ComplainRepository complainRepository, - ComplaintOptionsStatusMasterRepository complaintStatusMasterRepository) { + ComplaintOptionsStatusMasterRepository complaintStatusMasterRepository, + TransactionMasterRepository transactionMasterRepository) { this.restClient = restClient; this.httpService = httpService; this.helper = helper; @@ -77,7 +82,7 @@ public class ComplainServiceImpl implements ComplainService { this.mapperHelper = mapperHelper; this.complainRepository = complainRepository; this.complaintStatusMasterRepository = complaintStatusMasterRepository; - + this.transactionMasterRepository = transactionMasterRepository; // initialize shared ObjectMapper once this.objectMapper = new ObjectMapper(); this.objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); @@ -110,10 +115,20 @@ public class ComplainServiceImpl implements ComplainService { BBPSConstant.HTTP_POST, null); try { + + Optional dataById = transactionMasterRepository.findById(complainRequestDTO.getTxnId()); + if (dataById == null || dataById.isEmpty()) { + LOGGER.warn("Master Data By Id is null"); + throw new CustomException("Master Data is required", "FAILED", BBPSConstant.BADREQUEST, null); + } + + TransactionMaster transData = dataById.get(); // Inject tenantId + agentId into request JSON ObjectNode root = (ObjectNode) objectMapper.readTree(forwardJson); root.put("tenantId", headersData.getTenantId()); root.put("agentId", headersData.getAgentId()); + root.put("billerId", transData.getBillerId()); + root.put("billerName", transData.getBillerName()); String finalJson = root.toString(); LOGGER.info("[{}] Final Request Sent to API | reqId={} | payload={}", apiName, requestId, finalJson); diff --git a/src/main/java/com/billpaymentservice/bbps/serviceImpl/MasterDataServiceImpl.java b/src/main/java/com/billpaymentservice/bbps/serviceImpl/MasterDataServiceImpl.java index 70363d9..0804cb6 100644 --- a/src/main/java/com/billpaymentservice/bbps/serviceImpl/MasterDataServiceImpl.java +++ b/src/main/java/com/billpaymentservice/bbps/serviceImpl/MasterDataServiceImpl.java @@ -2,28 +2,35 @@ package com.billpaymentservice.bbps.serviceImpl; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; import org.modelmapper.ModelMapper; import org.modelmapper.convention.MatchingStrategies; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Service; + +import com.billpaymentservice.bbps.config.JwtUtil; import com.billpaymentservice.bbps.dto.CustomParamDTO; import com.billpaymentservice.bbps.dto.CustomerParamGroupsDTO; import com.billpaymentservice.bbps.dto.GeneralResp; import com.billpaymentservice.bbps.dto.MasterApiResponse; import com.billpaymentservice.bbps.dto.ResponseModel; +import com.billpaymentservice.bbps.dto.UserDetailsDTO; import com.billpaymentservice.bbps.dto.request.BillerDetailRequest; import com.billpaymentservice.bbps.dto.request.ContactMasterRequest; import com.billpaymentservice.bbps.dto.request.CustomParamRequest; import com.billpaymentservice.bbps.dto.request.DispositionRequest; +import com.billpaymentservice.bbps.dto.request.LoginRequest; import com.billpaymentservice.bbps.dto.request.MasterCategoryRequest; import com.billpaymentservice.bbps.dto.request.MasterRequest; import com.billpaymentservice.bbps.dto.request.PlanRequest; import com.billpaymentservice.bbps.dto.response.AmountOptionsResponse; +import com.billpaymentservice.bbps.dto.response.AuthResponse; import com.billpaymentservice.bbps.dto.response.BillerDataResponse; import com.billpaymentservice.bbps.dto.response.BillerResponse; import com.billpaymentservice.bbps.dto.response.ChannelsListResponse; @@ -42,6 +49,7 @@ import com.billpaymentservice.bbps.entites.DispositionDetails; import com.billpaymentservice.bbps.entites.InboundTraceLog; import com.billpaymentservice.bbps.entites.OutboundTraceLog; import com.billpaymentservice.bbps.entites.PlanResponses; +import com.billpaymentservice.bbps.entites.UsersDetails; import com.billpaymentservice.bbps.exception.CustomException; import com.billpaymentservice.bbps.repository.BharatConnectMasterRepository; import com.billpaymentservice.bbps.repository.BillerDataRepository; @@ -50,6 +58,7 @@ import com.billpaymentservice.bbps.repository.DispositionRepository; import com.billpaymentservice.bbps.repository.InboundTraceLogRepository; import com.billpaymentservice.bbps.repository.MerchantRepository; import com.billpaymentservice.bbps.repository.OutboundTraceLogRepository; +import com.billpaymentservice.bbps.repository.UsersDetailsRepository; import com.billpaymentservice.bbps.service.MasterDataService; import com.billpaymentservice.bbps.util.BBPSConstant; import com.billpaymentservice.bbps.util.BillerMapperHelper; @@ -80,6 +89,11 @@ public class MasterDataServiceImpl implements MasterDataService { private final InboundTraceLogRepository inboundTraceLogRepository; private final OutboundTraceLogRepository outboundTraceLogRepository; private final CustomParamRepository customParamReposiotory; + @Autowired + private UsersDetailsRepository userRepo; + + @Autowired + private JwtUtil jwtUtil; public MasterDataServiceImpl(MerchantRepository merchantRegisterRepo, HttpService httpService, HttpClientApi httpClientApi, Helper helper, BillerDataRepository billerDataRespository, @@ -224,7 +238,7 @@ public class MasterDataServiceImpl implements MasterDataService { throw new CustomException("Invalid JSON received from API"); } } - + @Override public ResponseModel getCustomerParamByBillerId(CustomParamRequest customerParamRequest) { String apiName = BBPSConstant.API_GET_CUSTOMER_PARAM_BY_BILLER_ID; @@ -366,7 +380,7 @@ public class MasterDataServiceImpl implements MasterDataService { LOGGER.info("[{}] START | reqId={} | mid={} | billerName={} | category={}", apiName, requestId, mid, masterRequest.getBillerName(), masterRequest.getCategory()); - String txnID = helper.generateTxnId(15); + String txnID = helper.generateTxnId(15); String fullUrl = String.format("%s%s?billerName=%s&category=%s&page=%d&pagesize=%d", masterRegisterUrl, BBPSConstant.BILLER_URL, masterRequest.getBillerName(), masterRequest.getCategory(), masterRequest.getPageNo(), masterRequest.getPageSize()); @@ -472,7 +486,7 @@ public class MasterDataServiceImpl implements MasterDataService { if (entities != null) { dispositionRepository.saveAll(entities); } else { - + LOGGER.warn("No disposition found in response to save."); } @@ -868,4 +882,40 @@ public class MasterDataServiceImpl implements MasterDataService { } } + @Override + public AuthResponse authenticateUser(LoginRequest loginRequest) { + LOGGER.info("Processing login for Request: " + loginRequest); + + try { + String mobileNo = loginRequest.getMobileNumber(); + + Optional byAdminEmail = userRepo.findByUserMobNo(mobileNo); + + if (byAdminEmail.isPresent()) { + UsersDetails user = byAdminEmail.get(); + String token = jwtUtil.generateToken(user.getUserMobNo()); + + LOGGER.info("Generated JWT token for mobileNo: " + mobileNo); + + Object userDetailsDTO = null; + + if (user != null) { + userDetailsDTO = UserDetailsDTO.builder().id(user.getId()).userEmailId(user.getUserEmailId()) + .userMobNo(user.getUserMobNo()).userName(user.getUserName()).userAge(user.getUserAge()) + .build(); + } + return new AuthResponse(token, "Success", "Login Done", 200, userDetailsDTO); + } else { + return new AuthResponse("", "User Not Found", "Authentication failed", 401, null); + } + + } catch (Exception ex) { + System.out.println("Error occurred during login for mobile no: " + loginRequest.getMobileNumber() + + " Exception: " + ex.getMessage()); + + return AuthResponse.builder().status("Unauthorized").message("Authentication failed: " + ex.getMessage()) + .statusCode(401).build(); + } + } + } \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/swagger/SwaggerConfig.java b/src/main/java/com/billpaymentservice/bbps/swagger/SwaggerConfig.java index 9be701f..735eab2 100644 --- a/src/main/java/com/billpaymentservice/bbps/swagger/SwaggerConfig.java +++ b/src/main/java/com/billpaymentservice/bbps/swagger/SwaggerConfig.java @@ -1,7 +1,5 @@ package com.billpaymentservice.bbps.swagger; -import java.util.List; - import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -9,7 +7,8 @@ import org.springframework.context.annotation.Configuration; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Contact; import io.swagger.v3.oas.models.info.Info; -import io.swagger.v3.oas.models.servers.Server; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; @Configuration public class SwaggerConfig { @@ -21,12 +20,14 @@ public class SwaggerConfig { private String serverDescription; @Bean - public OpenAPI openAPI() { - return new OpenAPI() - .info(new Info().title("BBPS API").description("Spring Boot REST API for BBPS System API Documentation") - .version("1.0.0").contact(new Contact().name("BBPS "))) - .servers(List.of(new Server().url(serverUrl).description(serverDescription))); - + public OpenAPI customOpenAPI() { + return new OpenAPI().addSecurityItem(new SecurityRequirement().addList("Authentication")) + .components(new io.swagger.v3.oas.models.Components().addSecuritySchemes("Authentication", + new SecurityScheme().name("Authentication").type(SecurityScheme.Type.APIKEY) + .in(SecurityScheme.In.HEADER))) + .info(new Info().title("Spring Boot REST API").description("Spring Boot REST API for BBPS") + .version("1.0.0").contact(new Contact().name("Globots").url(serverUrl) + .email("info@merchantpanel.com"))); } } diff --git a/src/main/java/com/billpaymentservice/bbps/util/BillerMapperHelper.java b/src/main/java/com/billpaymentservice/bbps/util/BillerMapperHelper.java index 72f1a52..059db76 100644 --- a/src/main/java/com/billpaymentservice/bbps/util/BillerMapperHelper.java +++ b/src/main/java/com/billpaymentservice/bbps/util/BillerMapperHelper.java @@ -1044,9 +1044,6 @@ public class BillerMapperHelper { public FetchComplaintForwardRequest fetchComplaintForwardRequestMap(ComplaintRequestDTO complainRequestDTO) { FetchComplaintForwardRequest forward = new FetchComplaintForwardRequest(); - - forward.setBillerId(complainRequestDTO.getBillerId()); - forward.setBillerName(complainRequestDTO.getBillerName()); forward.setTicketDescription(complainRequestDTO.getTicketDescription()); forward.setTicketDisposition(complainRequestDTO.getTicketDisposition()); forward.setTicketDispositionCode(complainRequestDTO.getTicketDispositionCode()); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index c652768..d32e5c2 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -19,6 +19,7 @@ swagger.server.description=Local Development Server spring.profiles.active=local + # DataSource spring.datasource.url=jdbc:postgresql://localhost:5432/BBPS spring.datasource.username=postgres @@ -44,7 +45,8 @@ logging.level.io.github.resilience4j.retry=DEBUG master.data.url = https://bbps-staging.digiledge.in/agent/cou-master/masters agent.data.url=https://bbps-staging.digiledge.in/agent/bill-payment-new payment.data.url=https://bbps-staging.digiledge.in/couapp -complaint.data.url=https://bbps-staging.digiledge.in +complaint.data.url=https://bbps-staging.digiledge.in/agent/bill-payment-new + # throw NoHandlerFoundException for 404s spring.mvc.throw-exception-if-no-handler-found=true @@ -55,6 +57,9 @@ spring.web.resources.add-mappings=false # (optional) to avoid path match issues on Spring Boot 2.6+ spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER +jwt.secret=6C756148487475787A414646736D4B6E444E585A766145396E6A4555594A595566657A6E434D62536856674A704C494F6C6E666B366A4A6A6D5630323564716C614F + + # Resilience4j Retry resilience4j.retry.instances.callbackService.max-attempts=1