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
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package co.nilin.opex.auth.config
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.HttpMethod
import org.springframework.security.config.Customizer
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity
import org.springframework.security.config.web.server.ServerHttpSecurity
Expand All @@ -27,6 +28,7 @@ class SecurityConfig(
.pathMatchers("/v1/oauth/protocol/openid-connect/**").permitAll()
.pathMatchers("/v1/oauth.***").permitAll()
.pathMatchers("/v1/user/public/**").permitAll()
.pathMatchers("/v1/user/update/**").permitAll()
.anyExchange().authenticated()
}
.oauth2ResourceServer { it.jwt(Customizer.withDefaults()) }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package co.nilin.opex.auth.controller

import co.nilin.opex.auth.model.UpdateEmailRequest
import co.nilin.opex.auth.model.UpdateMobileRequest
import co.nilin.opex.auth.model.UpdateNameRequest
import co.nilin.opex.auth.data.ActiveSession
import co.nilin.opex.auth.service.UserService
import co.nilin.opex.auth.utils.jwtAuthentication
Expand All @@ -17,6 +20,27 @@ class UserController(private val userService: UserService) {
userService.logout(securityContext.jwtAuthentication().name)
}

@PutMapping("/update/email")
suspend fun updateEmail(
@RequestBody request: UpdateEmailRequest
) {
userService.updateEmail(request)
}

@PutMapping("/update/mobile")
suspend fun updateMobile(
@RequestBody request: UpdateMobileRequest
) {
userService.updateMobile(request)

}

@PutMapping("/update/name")
suspend fun updateName(
@RequestBody request: UpdateNameRequest
) {
userService.updateName(request)
}
@GetMapping("/session")
suspend fun getSessions(@CurrentSecurityContext securityContext: SecurityContext): List<ActiveSession> {
val uuid = securityContext.authentication.name
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package co.nilin.opex.auth.model

data class UpdateMobileRequest(
val userId :String,
val mobile: String
)

data class UpdateEmailRequest(
val userId :String,
val email: String
)

data class UpdateNameRequest(
val userId :String,
val firstName: String,
val lastName: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,54 @@ class KeycloakProxy(
return this
}

suspend fun updateUserMobile(userId: String, newMobile: String) {
val url = "${keycloakConfig.url}/admin/realms/${keycloakConfig.realm}/users/$userId"
val patch = mapOf(
"attributes" to mapOf("mobile" to newMobile)
)
keycloakClient.put()
.uri(url)
.contentType(MediaType.APPLICATION_JSON)
.withAdminToken()
.bodyValue(patch)
.retrieve()
.toBodilessEntity()
.awaitSingleOrNull()
}

suspend fun updateUserEmail(userId: String, newEmail: String) {
val url = "${keycloakConfig.url}/admin/realms/${keycloakConfig.realm}/users/$userId"
val patch = mapOf(
"email" to newEmail,
"emailVerified" to true
)
keycloakClient.put()
.uri(url)
.contentType(MediaType.APPLICATION_JSON)
.withAdminToken()
.bodyValue(patch)
.retrieve()
.toBodilessEntity()
.awaitSingleOrNull()
}

suspend fun updateUserName(userId: String, firstName: String?, lastName: String?) {
val url = "${keycloakConfig.url}/admin/realms/${keycloakConfig.realm}/users/$userId"
val patch = mutableMapOf<String, Any>()

firstName?.let { patch["firstName"] = it }
lastName?.let { patch["lastName"] = it }

keycloakClient.put()
.uri(url)
.contentType(MediaType.APPLICATION_JSON)
.withAdminToken()
.bodyValue(patch)
.retrieve()
.toBodilessEntity()
.awaitSingleOrNull()
}

private suspend fun generateRandomInternalID(): String {
var internalId: String;
var attempts = 0
Expand All @@ -373,5 +421,6 @@ class KeycloakProxy(
attempts++
} while (findUserByAttribute(Attribute("username", internalId)).isNotEmpty())
return internalId

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,18 @@ class UserService(
keycloakProxy.resetPassword(user.id, request.newPassword)
}

suspend fun updateMobile(request: UpdateMobileRequest) {
keycloakProxy.updateUserMobile(request.userId, request.mobile)
}

suspend fun updateEmail(request: UpdateEmailRequest) {
keycloakProxy.updateUserEmail(request.userId, request.email)
}

suspend fun updateName(request: UpdateNameRequest) {
keycloakProxy.updateUserName(request.userId, request.firstName, request.lastName)
}

suspend fun fetchActiveSessions(uuid: String, currentSessionId: String): List<ActiveSession> {
return keycloakProxy.fetchActiveSessions(uuid, currentSessionId)
}
Expand Down Expand Up @@ -202,6 +214,5 @@ class UserService(
return TokenData(false, "", OTPAction.REGISTER)
}
}

}

29 changes: 21 additions & 8 deletions common/src/main/kotlin/co/nilin/opex/common/OpexError.kt
Original file line number Diff line number Diff line change
Expand Up @@ -141,14 +141,27 @@ enum class OpexError(val code: Int, val message: String?, val status: HttpStatus


//code 12000 profile
UserIdAlreadyExists(130001, "User with this id or email is already registered", HttpStatus.BAD_REQUEST),
InvalidLinkedAccount(130002, "Irrelevant account", HttpStatus.BAD_REQUEST),
AccountNotFound(130003, " Account not found", HttpStatus.BAD_REQUEST),
DuplicateAccount(130004, " Duplicate account", HttpStatus.BAD_REQUEST),
InvalidIban(130005, " Invalid iban number", HttpStatus.BAD_REQUEST),
InvalidCard(130006, " Invalid card number", HttpStatus.BAD_REQUEST),
VerificationFailed(130007, "Verification Failed", HttpStatus.BAD_REQUEST),
ProfileApprovalRequestAlreadyExists(130008, "Request Already Exists", HttpStatus.BAD_REQUEST),
UserIdAlreadyExists(13001, "User with this id or email is already registered", HttpStatus.BAD_REQUEST),
InvalidLinkedAccount(13002, "Irrelevant account", HttpStatus.BAD_REQUEST),
AccountNotFound(13003, " Account not found", HttpStatus.BAD_REQUEST),
DuplicateAccount(13004, " Duplicate account", HttpStatus.BAD_REQUEST),
InvalidIban(13005, " Invalid iban number", HttpStatus.BAD_REQUEST),
InvalidCard(13006, " Invalid card number", HttpStatus.BAD_REQUEST),
ShahkarVerificationFailed(13007, "Shahkar Verification Failed", HttpStatus.BAD_REQUEST),
ProfileApprovalRequestAlreadyExists(13008, "Request Already Exists", HttpStatus.BAD_REQUEST),
ProfileNotfound(13009, "Profile not found", HttpStatus.NOT_FOUND),
EmailAlreadyExists(13010, "Email already exists", HttpStatus.BAD_REQUEST),
MobileAlreadyExists(13011, "Mobile already exists", HttpStatus.BAD_REQUEST),
InvalidEmail(13012, "Invalid email", HttpStatus.BAD_REQUEST),
InvalidMobile(13013, "Invalid mobile", HttpStatus.BAD_REQUEST),
MobileAlreadySet(13014, "Mobile already set", HttpStatus.BAD_REQUEST),
EmailAlreadySet(13015, "Email already set", HttpStatus.BAD_REQUEST),
ProfileAlreadyCompleted(13016, "Profile already completed", HttpStatus.BAD_REQUEST),
ComparativeVerificationFailed(13017, "Comparative Verification Failed", HttpStatus.BAD_REQUEST),
ProfileApprovalRequestNotfound(13018, "Profile approval request not found", HttpStatus.NOT_FOUND),
InvalidProfileApprovalRequestStatus(13018, "Invalid profile approval request status", HttpStatus.BAD_REQUEST),
ShahkarInquiryUnavailable(13019,"Shahkar inquiry unavailable" , HttpStatus.SERVICE_UNAVAILABLE),
ComparativeInquiryUnavailable(13020,"Comparative inquiry unavailable" , HttpStatus.SERVICE_UNAVAILABLE),
;

override fun code() = this.code
Expand Down
5 changes: 4 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -528,13 +528,16 @@ services:
profile:
image: ghcr.io/opexdev/profile
environment:
- JAVA_OPTS=-Xmx256m -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
- JAVA_OPTS=-Xmx256m -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
- CONSUL_HOST=consul
- DB_IP_PORT=postgres-profile
- KAFKA_IP_PORT=kafka-1:29092,kafka-2:29092,kafka-3:29092
- BACKEND_USER=${BACKEND_USER}
- VAULT_HOST=vault
- SWAGGER_AUTH_URL=$KEYCLOAK_FRONTEND_URL
- JIBIT_URL=${JIBIT_URL}
- JIBIT_API_KEY=${JIBIT_API_KEY}
- JIBIT_SECRET_KEY=${JIBIT_SECRET_KEY}
depends_on:
- kafka-1
- kafka-2
Expand Down
16 changes: 14 additions & 2 deletions profile/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
<module>profile-ports/profile-eventlistener-kafka</module>
<module>profile-ports/profile-submitter-kafka</module>
<module>profile-ports/profile-kyc-proxy</module>
<module>profile-ports/profile-shahkar-proxy</module>
<module>profile-ports/profile-inquiry-proxy</module>
<module>profile-ports/profile-otp-proxy</module>
<module>profile-ports/profile-auth-proxy</module>
</modules>

<dependencyManagement>
Expand Down Expand Up @@ -77,7 +79,17 @@
</dependency>
<dependency>
<groupId>co.nilin.opex.profile.ports</groupId>
<artifactId>profile-shahkar-proxy</artifactId>
<artifactId>profile-inquiry-proxy</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>co.nilin.opex.profile.ports</groupId>
<artifactId>profile-otp-proxy</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>co.nilin.opex.profile.ports</groupId>
<artifactId>profile-auth-proxy</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
Expand Down
8 changes: 8 additions & 0 deletions profile/profile-app/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@
<groupId>co.nilin.opex.profile.ports</groupId>
<artifactId>profile-submitter-kafka</artifactId>
</dependency>
<dependency>
<groupId>co.nilin.opex.profile.ports</groupId>
<artifactId>profile-otp-proxy</artifactId>
</dependency>
<dependency>
<groupId>co.nilin.opex.profile.ports</groupId>
<artifactId>profile-auth-proxy</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ class SecurityConfig(private val webClient: WebClient) {
fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain? {
http.csrf().disable()
.authorizeExchange()
// .pathMatchers("/**").permitAll()
.pathMatchers("**/admin/**").hasRole("SCOPE_trust", "admin_system")
.pathMatchers("/admin/**").hasAuthority("ROLE_admin")
.pathMatchers("/actuator/**").permitAll()
.anyExchange().authenticated()
.and()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,35 @@ class WebClientConfig {
@Qualifier("loadBalanced")
fun loadBalancedWebClient(loadBalancerFactory: ReactiveLoadBalancer.Factory<ServiceInstance>): WebClient {
return WebClient.builder()
.filter(ReactorLoadBalancerExchangeFilterFunction(loadBalancerFactory, emptyList()))
.exchangeStrategies(
ExchangeStrategies.builder()
.codecs { it.defaultCodecs().maxInMemorySize(20 * 1024 * 1024) }
.build()
)
.build()
.filter(ReactorLoadBalancerExchangeFilterFunction(loadBalancerFactory, emptyList()))
.exchangeStrategies(
ExchangeStrategies.builder()
.codecs { it.defaultCodecs().maxInMemorySize(20 * 1024 * 1024) }
.build()
)
.build()
}

@Bean
fun webClient(loadBalancerFactory: ReactiveLoadBalancer.Factory<ServiceInstance>): WebClient {
return WebClient.builder()
.filter(
ReactorLoadBalancerExchangeFilterFunction(
loadBalancerFactory, LoadBalancerProperties(), emptyList()
)
.filter(
ReactorLoadBalancerExchangeFilterFunction(
loadBalancerFactory, LoadBalancerProperties(), emptyList()
)
.build()
)
.build()
}

@Bean
@Qualifier("plainWebClient")
fun plainWebClient(): WebClient {
return WebClient.builder()
.exchangeStrategies(
ExchangeStrategies.builder()
.codecs { it.defaultCodecs().maxInMemorySize(20 * 1024 * 1024) }
.build()
)
.build()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import org.springframework.security.core.context.SecurityContext
import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("/v2/admin/profile")
@RequestMapping("/admin/profile")

class ProfileAdminController(
val profileManagement: ProfileManagement,
Expand Down
Loading
Loading