mirror of
https://github.com/OpenBankProject/OBP-API.git
synced 2026-02-06 13:07:02 +00:00
Merge pull request #2176 from hongwei1/develop
bugfix/fixed the getUserByUsername issue
This commit is contained in:
commit
23f6ca7eac
@ -166,11 +166,10 @@ object OAuth2Login extends RestHelper with MdcLoggable {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val user = Users.users.vend.getUserByUserName(introspectOAuth2Token.getSub)
|
||||
val user = Users.users.vend.getUserByUserName(hydraPublicUrl, introspectOAuth2Token.getSub)
|
||||
user match {
|
||||
case Full(u) =>
|
||||
LoginAttempt.userIsLocked(u.name) match {
|
||||
LoginAttempt.userIsLocked(u.provider, u.name) match {
|
||||
case true => (Failure(UsernameHasBeenLocked), Some(cc.copy(consumer = consumer)))
|
||||
case false => (Full(u), Some(cc.copy(consumer = consumer)))
|
||||
}
|
||||
@ -349,7 +348,7 @@ object OAuth2Login extends RestHelper with MdcLoggable {
|
||||
case Full(_) =>
|
||||
val user = IdentityProviderCommon.getOrCreateResourceUser(value)
|
||||
val consumer = IdentityProviderCommon.getOrCreateConsumer(value, user.map(_.userId))
|
||||
LoginAttempt.userIsLocked(user.map(_.name).getOrElse("")) match {
|
||||
LoginAttempt.userIsLocked(user.map(_.provider).getOrElse(""), user.map(_.name).getOrElse("")) match {
|
||||
case true => ((Failure(UsernameHasBeenLocked), Some(cc.copy(consumer = consumer))))
|
||||
case false => (user, Some(cc.copy(consumer = consumer)))
|
||||
}
|
||||
@ -368,7 +367,7 @@ object OAuth2Login extends RestHelper with MdcLoggable {
|
||||
user <- IdentityProviderCommon.getOrCreateResourceUserFuture(value)
|
||||
consumer <- Future{IdentityProviderCommon.getOrCreateConsumer(value, user.map(_.userId))}
|
||||
} yield {
|
||||
LoginAttempt.userIsLocked(user.map(_.name).getOrElse("")) match {
|
||||
LoginAttempt.userIsLocked(user.map(_.provider).getOrElse(""), user.map(_.name).getOrElse("")) match {
|
||||
case true => ((Failure(UsernameHasBeenLocked), Some(cc.copy(consumer = consumer))))
|
||||
case false => (user, Some(cc.copy(consumer = consumer)))
|
||||
}
|
||||
|
||||
@ -352,7 +352,7 @@ trait OBPRestHelper extends RestHelper with MdcLoggable {
|
||||
if(u.isDeleted.getOrElse(false)) {
|
||||
Failure(UserIsDeleted) // The user is DELETED.
|
||||
} else {
|
||||
LoginAttempt.userIsLocked(u.name) match {
|
||||
LoginAttempt.userIsLocked(u.provider, u.name) match {
|
||||
case true => Failure(UsernameHasBeenLocked) // The user is LOCKED.
|
||||
case false => function(callContext) // All good
|
||||
}
|
||||
|
||||
@ -139,7 +139,7 @@ object DAuth extends RestHelper with MdcLoggable {
|
||||
logger.debug("login_user_name: " + userName)
|
||||
for {
|
||||
tuple <-
|
||||
UserX.getOrCreateDauthResourceUser(userName, provider) match {
|
||||
UserX.getOrCreateDauthResourceUser(provider, userName) match {
|
||||
case Full(u) =>
|
||||
Full((u,callContext)) // Return user
|
||||
case Empty =>
|
||||
@ -159,7 +159,7 @@ object DAuth extends RestHelper with MdcLoggable {
|
||||
logger.debug("login_user_name: " + username)
|
||||
|
||||
for {
|
||||
tuple <- Future { UserX.getOrCreateDauthResourceUser(username, provider)} map {
|
||||
tuple <- Future { UserX.getOrCreateDauthResourceUser(provider, username)} map {
|
||||
case (Full(u)) =>
|
||||
Full(u, callContext) // Return user
|
||||
case (Empty) =>
|
||||
|
||||
@ -123,7 +123,7 @@ object OpenIdConnect extends OBPRestHelper with MdcLoggable {
|
||||
JwtUtil.validateIdToken(idToken, OpenIdConnectConfig.get(identityProvider).jwks_uri) match {
|
||||
case Full(_) =>
|
||||
getOrCreateResourceUser(idToken) match {
|
||||
case Full(user) if LoginAttempt.userIsLocked(user.name) => // User is locked
|
||||
case Full(user) if LoginAttempt.userIsLocked(user.provider, user.name) => // User is locked
|
||||
(401, ErrorMessages.UsernameHasBeenLocked, None)
|
||||
case Full(user) => // All good
|
||||
getOrCreateAuthUser(user) match {
|
||||
|
||||
@ -68,7 +68,7 @@ object AfterApiAuth extends MdcLoggable{
|
||||
if (u.isDeleted.getOrElse(false)) {
|
||||
(Failure(UserIsDeleted), cc) // The user is DELETED.
|
||||
} else {
|
||||
LoginAttempt.userIsLocked(u.name) match {
|
||||
LoginAttempt.userIsLocked(u.provider, u.name) match {
|
||||
case true => (Failure(UsernameHasBeenLocked), cc) // The user is LOCKED.
|
||||
case false => (user, cc) // All good
|
||||
}
|
||||
|
||||
@ -151,7 +151,7 @@ object ErrorMessages {
|
||||
val ScopeNotFound = "OBP-20025: Scope not found. Please specify a valid value for SCOPE_ID."
|
||||
val ConsumerDoesNotHaveScope = "OBP-20026: CONSUMER_ID does not have the SCOPE_ID "
|
||||
|
||||
val UserNotFoundByUsername = "OBP-20027: User not found by username."
|
||||
val UserNotFoundByProviderAndUsername = "OBP-20027: User not found by provider and username."
|
||||
val GatewayLoginMissingParameters = "OBP-20028: These GatewayLogin parameters are missing:"
|
||||
val GatewayLoginUnknownError = "OBP-20029: Unknown Gateway login error."
|
||||
val GatewayLoginHostPropertyMissing = "OBP-20030: Property gateway.host is not defined."
|
||||
@ -721,7 +721,7 @@ object ErrorMessages {
|
||||
UserNoPermissionAccessView -> 403,
|
||||
UserNotSuperAdminOrMissRole -> 403,
|
||||
ConsumerHasMissingRoles -> 403,
|
||||
UserNotFoundByUsername -> 404,
|
||||
UserNotFoundByProviderAndUsername -> 404,
|
||||
ApplicationNotIdentified -> 401,
|
||||
CouldNotExchangeAuthorizationCodeForTokens -> 401,
|
||||
CouldNotSaveOpenIDConnectUser -> 401,
|
||||
|
||||
@ -1134,8 +1134,8 @@ object NewStyle extends MdcLoggable{
|
||||
}
|
||||
}
|
||||
|
||||
def getOrCreateResourceUser(username: String, provider: String, callContext: Option[CallContext]): OBPReturnType[User] = {
|
||||
Future { UserX.getOrCreateDauthResourceUser(username, provider).map(user =>(user, callContext))} map {
|
||||
def getOrCreateResourceUser(provider: String, username: String, callContext: Option[CallContext]): OBPReturnType[User] = {
|
||||
Future { UserX.getOrCreateDauthResourceUser(provider, username).map(user =>(user, callContext))} map {
|
||||
unboxFullOrFail(_, callContext, s"$CannotGetOrCreateUser Current USERName($username) PROVIDER ($provider)", 404)
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,6 +96,7 @@ object Migration extends MdcLoggable {
|
||||
alterMappedExpectedChallengeAnswerChallengeTypeLength()
|
||||
alterTransactionRequestChallengeChallengeTypeLength()
|
||||
alterMappedCustomerAttribute(startedBeforeSchemifier)
|
||||
dropMappedBadLoginAttemptIndex()
|
||||
}
|
||||
|
||||
private def dummyScript(): Boolean = {
|
||||
@ -431,6 +432,13 @@ object Migration extends MdcLoggable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def dropMappedBadLoginAttemptIndex(): Boolean = {
|
||||
val name = nameOf(dropMappedBadLoginAttemptIndex)
|
||||
runOnce(name) {
|
||||
MigrationOfMappedBadLoginAttemptDropIndex.dropUniqueIndex(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -0,0 +1,83 @@
|
||||
package code.api.util.migration
|
||||
|
||||
import code.api.Constant
|
||||
import code.api.util.APIUtil
|
||||
import code.api.util.migration.Migration.{DbFunction, saveLog}
|
||||
import code.loginattempts.MappedBadLoginAttempt
|
||||
import net.liftweb.mapper.{DB, Schemifier}
|
||||
import net.liftweb.util.DefaultConnectionIdentifier
|
||||
import scalikejdbc.DB.CPContext
|
||||
import scalikejdbc._
|
||||
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.{ZoneId, ZonedDateTime}
|
||||
|
||||
object MigrationOfMappedBadLoginAttemptDropIndex {
|
||||
|
||||
val oneDayAgo = ZonedDateTime.now(ZoneId.of("UTC")).minusDays(1)
|
||||
val oneYearInFuture = ZonedDateTime.now(ZoneId.of("UTC")).plusYears(1)
|
||||
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm'Z'")
|
||||
|
||||
private lazy val getDbConnectionParameters: (String, String, String) = {
|
||||
val dbUrl = APIUtil.getPropsValue("db.url") openOr Constant.h2DatabaseDefaultUrlValue
|
||||
val username = dbUrl.split(";").filter(_.contains("user")).toList.headOption.map(_.split("=")(1))
|
||||
val password = dbUrl.split(";").filter(_.contains("password")).toList.headOption.map(_.split("=")(1))
|
||||
val dbUser = APIUtil.getPropsValue("db.user").orElse(username)
|
||||
val dbPassword = APIUtil.getPropsValue("db.password").orElse(password)
|
||||
(dbUrl, dbUser.getOrElse(""), dbPassword.getOrElse(""))
|
||||
}
|
||||
|
||||
/**
|
||||
* this connection pool context corresponding db.url in default.props
|
||||
*/
|
||||
implicit lazy val context: CPContext = {
|
||||
val settings = ConnectionPoolSettings(
|
||||
initialSize = 5,
|
||||
maxSize = 20,
|
||||
connectionTimeoutMillis = 3000L,
|
||||
validationQuery = "select 1",
|
||||
connectionPoolFactoryName = "commons-dbcp2"
|
||||
)
|
||||
val (dbUrl, user, password) = getDbConnectionParameters
|
||||
val dbName = "DB_NAME" // corresponding props db.url DB
|
||||
ConnectionPool.add(dbName, dbUrl, user, password, settings)
|
||||
val connectionPool = ConnectionPool.get(dbName)
|
||||
MultipleConnectionPoolContext(ConnectionPool.DEFAULT_NAME -> connectionPool)
|
||||
}
|
||||
|
||||
def dropUniqueIndex(name: String): Boolean = {
|
||||
DbFunction.tableExists(MappedBadLoginAttempt, (DB.use(DefaultConnectionIdentifier){ conn => conn})) match {
|
||||
case true =>
|
||||
val startDate = System.currentTimeMillis()
|
||||
val commitId: String = APIUtil.gitCommit
|
||||
var isSuccessful = false
|
||||
|
||||
val executedSql =
|
||||
DbFunction.maybeWrite(true, Schemifier.infoF _, DB.use(DefaultConnectionIdentifier){ conn => conn}) {
|
||||
APIUtil.getPropsValue("db.driver") match {
|
||||
case _ =>
|
||||
() => "DROP INDEX IF EXISTS mappedbadloginattempt_musername;"
|
||||
}
|
||||
}
|
||||
|
||||
val endDate = System.currentTimeMillis()
|
||||
val comment: String =
|
||||
s"""Executed SQL:
|
||||
|$executedSql
|
||||
|""".stripMargin
|
||||
isSuccessful = true
|
||||
saveLog(name, commitId, isSuccessful, startDate, endDate, comment)
|
||||
isSuccessful
|
||||
|
||||
case false =>
|
||||
val startDate = System.currentTimeMillis()
|
||||
val commitId: String = APIUtil.gitCommit
|
||||
val isSuccessful = false
|
||||
val endDate = System.currentTimeMillis()
|
||||
val comment: String =
|
||||
s"""${MappedBadLoginAttempt._dbTableNameLC} table does not exist""".stripMargin
|
||||
saveLog(name, commitId, isSuccessful, startDate, endDate, comment)
|
||||
isSuccessful
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3,7 +3,7 @@ package code.api.v3_0_0
|
||||
import java.util.regex.Pattern
|
||||
import code.accountattribute.AccountAttributeX
|
||||
import code.accountholders.AccountHolders
|
||||
import code.api.APIFailureNewStyle
|
||||
import code.api.{APIFailureNewStyle, Constant}
|
||||
import code.api.Constant.{PARAM_LOCALE, PARAM_TIMESTAMP}
|
||||
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
|
||||
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.{bankJSON, banksJSON, branchJsonV300, _}
|
||||
@ -975,7 +975,7 @@ trait APIMethods300 {
|
||||
""".stripMargin,
|
||||
EmptyBody,
|
||||
usersJsonV200,
|
||||
List(UserNotLoggedIn, UserHasMissingRoles, UserNotFoundByUsername, UnknownError),
|
||||
List(UserNotLoggedIn, UserHasMissingRoles, UserNotFoundByProviderAndUsername, UnknownError),
|
||||
List(apiTagUser, apiTagNewStyle),
|
||||
Some(List(canGetAnyUser)))
|
||||
|
||||
@ -986,8 +986,8 @@ trait APIMethods300 {
|
||||
for {
|
||||
(Full(u), callContext) <- authenticatedAccess(cc)
|
||||
_ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canGetAnyUser, callContext)
|
||||
user <- Users.users.vend.getUserByUserNameFuture(username) map {
|
||||
x => unboxFullOrFail(x, callContext, UserNotFoundByUsername, 404)
|
||||
user <- Users.users.vend.getUserByProviderAndUsernameFuture(Constant.localIdentityProvider, username) map {
|
||||
x => unboxFullOrFail(x, callContext, UserNotFoundByProviderAndUsername, 404)
|
||||
}
|
||||
entitlements <- NewStyle.function.getEntitlementsByUserId(user.userId, callContext)
|
||||
} yield {
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package code.api.v3_1_0
|
||||
|
||||
import code.api.Constant.localIdentityProvider
|
||||
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.UUID
|
||||
import java.util.regex.Pattern
|
||||
@ -499,7 +501,7 @@ trait APIMethods310 {
|
||||
|""".stripMargin,
|
||||
EmptyBody,
|
||||
badLoginStatusJson,
|
||||
List(UserNotLoggedIn, UserNotFoundByUsername, UserHasMissingRoles, UnknownError),
|
||||
List(UserNotLoggedIn, UserNotFoundByProviderAndUsername, UserHasMissingRoles, UnknownError),
|
||||
List(apiTagUser, apiTagNewStyle),
|
||||
Some(List(canReadUserLockedStatus))
|
||||
)
|
||||
@ -511,7 +513,7 @@ trait APIMethods310 {
|
||||
for {
|
||||
(Full(u), callContext) <- authenticatedAccess(cc)
|
||||
_ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canReadUserLockedStatus, callContext)
|
||||
badLoginStatus <- Future { LoginAttempt.getBadLoginStatus(username) } map { unboxFullOrFail(_, callContext, s"$UserNotFoundByUsername($username)", 404) }
|
||||
badLoginStatus <- Future { LoginAttempt.getBadLoginStatus(localIdentityProvider, username) } map { unboxFullOrFail(_, callContext, s"$UserNotFoundByProviderAndUsername($username)", 404) }
|
||||
} yield {
|
||||
(createBadLoginStatusJson(badLoginStatus), HttpCode.`200`(callContext))
|
||||
}
|
||||
@ -535,7 +537,7 @@ trait APIMethods310 {
|
||||
|""".stripMargin,
|
||||
EmptyBody,
|
||||
badLoginStatusJson,
|
||||
List(UserNotLoggedIn, UserNotFoundByUsername, UserHasMissingRoles, UnknownError),
|
||||
List(UserNotLoggedIn, UserNotFoundByProviderAndUsername, UserHasMissingRoles, UnknownError),
|
||||
List(apiTagUser, apiTagNewStyle),
|
||||
Some(List(canUnlockUser)))
|
||||
|
||||
@ -546,9 +548,9 @@ trait APIMethods310 {
|
||||
for {
|
||||
(Full(u), callContext) <- authenticatedAccess(cc)
|
||||
_ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canUnlockUser, callContext)
|
||||
_ <- Future { LoginAttempt.resetBadLoginAttempts(username) }
|
||||
_ <- Future { UserLocksProvider.unlockUser(username) }
|
||||
badLoginStatus <- Future { LoginAttempt.getBadLoginStatus(username) } map { unboxFullOrFail(_, callContext, s"$UserNotFoundByUsername($username)", 404) }
|
||||
_ <- Future { LoginAttempt.resetBadLoginAttempts(localIdentityProvider,username) }
|
||||
_ <- Future { UserLocksProvider.unlockUser(localIdentityProvider,username) }
|
||||
badLoginStatus <- Future { LoginAttempt.getBadLoginStatus(localIdentityProvider, username) } map { unboxFullOrFail(_, callContext, s"$UserNotFoundByProviderAndUsername($username)", 404) }
|
||||
} yield {
|
||||
(createBadLoginStatusJson(badLoginStatus), HttpCode.`200`(callContext))
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ import java.util.{Calendar, Date}
|
||||
import code.DynamicData.{DynamicData, DynamicDataProvider}
|
||||
import code.DynamicEndpoint.DynamicEndpointSwagger
|
||||
import code.accountattribute.AccountAttributeX
|
||||
import code.api.Constant.{PARAM_LOCALE, PARAM_TIMESTAMP}
|
||||
import code.api.Constant.{PARAM_LOCALE, PARAM_TIMESTAMP, localIdentityProvider}
|
||||
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
|
||||
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.{jsonDynamicResourceDoc, _}
|
||||
import code.api.UKOpenBanking.v2_0_0.OBP_UKOpenBanking_200
|
||||
@ -2799,7 +2799,7 @@ trait APIMethods400 {
|
||||
|""".stripMargin,
|
||||
EmptyBody,
|
||||
userLockStatusJson,
|
||||
List($UserNotLoggedIn, UserNotFoundByUsername, UserHasMissingRoles, UnknownError),
|
||||
List($UserNotLoggedIn, UserNotFoundByProviderAndUsername, UserHasMissingRoles, UnknownError),
|
||||
List(apiTagUser, apiTagNewStyle),
|
||||
Some(List(canLockUser)))
|
||||
|
||||
@ -2808,8 +2808,8 @@ trait APIMethods400 {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- SS.user
|
||||
userLocks <- Future { UserLocksProvider.lockUser(username) } map {
|
||||
unboxFullOrFail(_, callContext, s"$UserNotFoundByUsername($username)", 404)
|
||||
userLocks <- Future { UserLocksProvider.lockUser(localIdentityProvider,username) } map {
|
||||
unboxFullOrFail(_, callContext, s"$UserNotFoundByProviderAndUsername($username)", 404)
|
||||
}
|
||||
} yield {
|
||||
(JSONFactory400.createUserLockStatusJson(userLocks), HttpCode.`200`(callContext))
|
||||
@ -2889,7 +2889,7 @@ trait APIMethods400 {
|
||||
|
||||
canCreateEntitlementAtAnyBankRole = Entitlement.entitlement.vend.getEntitlement("", loggedInUser.userId, canCreateEntitlementAtAnyBank.toString())
|
||||
|
||||
(targetUser, callContext) <- NewStyle.function.getOrCreateResourceUser(postedData.username, postedData.provider, callContext)
|
||||
(targetUser, callContext) <- NewStyle.function.getOrCreateResourceUser(postedData.provider, postedData.username, callContext)
|
||||
|
||||
_ <- if (canCreateEntitlementAtAnyBankRole.isDefined) {
|
||||
//If the loggedIn User has `CanCreateEntitlementAtAnyBankRole` role, then we can grant all the requestRoles to the requestUser.
|
||||
@ -3633,7 +3633,7 @@ trait APIMethods400 {
|
||||
acceptMarketingInfo <- NewStyle.function.getAgreementByUserId(user.userId, "accept_marketing_info", cc.callContext)
|
||||
termsAndConditions <- NewStyle.function.getAgreementByUserId(user.userId, "terms_and_conditions", cc.callContext)
|
||||
privacyConditions <- NewStyle.function.getAgreementByUserId(user.userId, "privacy_conditions", cc.callContext)
|
||||
isLocked = LoginAttempt.userIsLocked(user.name)
|
||||
isLocked = LoginAttempt.userIsLocked(user.provider, user.name)
|
||||
} yield {
|
||||
val agreements = acceptMarketingInfo.toList ::: termsAndConditions.toList ::: privacyConditions.toList
|
||||
(JSONFactory400.createUserInfoJSON(user, entitlements, Some(agreements), isLocked), HttpCode.`200`(cc.callContext))
|
||||
@ -3657,7 +3657,7 @@ trait APIMethods400 {
|
||||
""".stripMargin,
|
||||
EmptyBody,
|
||||
userJsonV400,
|
||||
List($UserNotLoggedIn, UserHasMissingRoles, UserNotFoundByUsername, UnknownError),
|
||||
List($UserNotLoggedIn, UserHasMissingRoles, UserNotFoundByProviderAndUsername, UnknownError),
|
||||
List(apiTagUser, apiTagNewStyle),
|
||||
Some(List(canGetAnyUser)))
|
||||
|
||||
@ -3666,11 +3666,11 @@ trait APIMethods400 {
|
||||
case "users" :: "username" :: username :: Nil JsonGet _ => {
|
||||
cc =>
|
||||
for {
|
||||
user <- Users.users.vend.getUserByUserNameFuture(username) map {
|
||||
x => unboxFullOrFail(x, cc.callContext, UserNotFoundByUsername, 404)
|
||||
user <- Users.users.vend.getUserByProviderAndUsernameFuture(Constant.localIdentityProvider, username) map {
|
||||
x => unboxFullOrFail(x, cc.callContext, UserNotFoundByProviderAndUsername, 404)
|
||||
}
|
||||
entitlements <- NewStyle.function.getEntitlementsByUserId(user.userId, cc.callContext)
|
||||
isLocked = LoginAttempt.userIsLocked(user.name)
|
||||
isLocked = LoginAttempt.userIsLocked(user.provider, user.name)
|
||||
} yield {
|
||||
(JSONFactory400.createUserInfoJSON(user, entitlements, None, isLocked), HttpCode.`200`(cc.callContext))
|
||||
}
|
||||
@ -4405,7 +4405,7 @@ trait APIMethods400 {
|
||||
}
|
||||
|
||||
_ <- NewStyle.function.canGrantAccessToView(bankId, accountId, cc.loggedInUser, cc.callContext)
|
||||
(targetUser, callContext) <- NewStyle.function.getOrCreateResourceUser(postJson.username, postJson.provider, cc.callContext)
|
||||
(targetUser, callContext) <- NewStyle.function.getOrCreateResourceUser(postJson.provider, postJson.username, cc.callContext)
|
||||
views <- getViews(bankId, accountId, postJson, callContext)
|
||||
addedView <- grantMultpleAccountAccessToUser(bankId, accountId, targetUser, views, callContext)
|
||||
} yield {
|
||||
|
||||
@ -1125,7 +1125,7 @@ object JSONFactory400 {
|
||||
t._1,
|
||||
t._2.getOrElse(Nil),
|
||||
t._3,
|
||||
LoginAttempt.userIsLocked(t._1.name)
|
||||
LoginAttempt.userIsLocked(t._1.provider, t._1.name)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@ -2,16 +2,21 @@ package code.api.v5_1_0
|
||||
|
||||
|
||||
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON.{apiCollectionJson400, apiCollectionsJson400, apiInfoJson400, postApiCollectionJson400, revokedConsentJsonV310}
|
||||
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON._
|
||||
import code.api.util.APIUtil._
|
||||
import code.api.util.ApiRole._
|
||||
import code.api.util.ApiTag._
|
||||
import code.api.util.ErrorMessages.{$UserNotLoggedIn, BankNotFound, ConsentNotFound, InvalidJsonFormat, UnknownError, UserNotFoundByUserId, UserNotLoggedIn, _}
|
||||
import code.api.util.NewStyle
|
||||
import code.api.util.{ApiRole, NewStyle}
|
||||
import code.api.util.NewStyle.HttpCode
|
||||
import code.api.v3_1_0.ConsentJsonV310
|
||||
import code.api.v3_1_0.JSONFactory310.createBadLoginStatusJson
|
||||
import code.api.v4_0_0.{JSONFactory400, PostApiCollectionJson400}
|
||||
import code.consent.Consents
|
||||
import code.loginattempts.LoginAttempt
|
||||
import code.transactionrequests.TransactionRequests.TransactionRequestTypes.{apply => _}
|
||||
import code.userlocks.UserLocksProvider
|
||||
import code.users.Users
|
||||
import code.util.Helper
|
||||
import com.github.dwickern.macros.NameOf.nameOf
|
||||
import com.openbankproject.commons.ExecutionContext.Implicits.global
|
||||
@ -199,7 +204,155 @@ trait APIMethods510 {
|
||||
}
|
||||
|
||||
|
||||
staticResourceDocs += ResourceDoc(
|
||||
getUserByProviderAndUsername,
|
||||
implementedInApiVersion,
|
||||
nameOf(getUserByProviderAndUsername),
|
||||
"GET",
|
||||
"/users/provider/PROVIDER/username/USERNAME",
|
||||
"Get User by USERNAME",
|
||||
s"""Get user by PROVIDER and USERNAME
|
||||
|
|
||||
|${authenticationRequiredMessage(true)}
|
||||
|
|
||||
|CanGetAnyUser entitlement is required,
|
||||
|
|
||||
""".stripMargin,
|
||||
EmptyBody,
|
||||
userJsonV400,
|
||||
List($UserNotLoggedIn, UserHasMissingRoles, UserNotFoundByProviderAndUsername, UnknownError),
|
||||
List(apiTagUser, apiTagNewStyle),
|
||||
Some(List(canGetAnyUser))
|
||||
)
|
||||
|
||||
lazy val getUserByProviderAndUsername: OBPEndpoint = {
|
||||
case "users" :: "provider" :: provider :: "username" :: username :: Nil JsonGet _ => {
|
||||
cc =>
|
||||
for {
|
||||
user <- Users.users.vend.getUserByProviderAndUsernameFuture(provider, username) map {
|
||||
x => unboxFullOrFail(x, cc.callContext, UserNotFoundByProviderAndUsername, 404)
|
||||
}
|
||||
entitlements <- NewStyle.function.getEntitlementsByUserId(user.userId, cc.callContext)
|
||||
isLocked = LoginAttempt.userIsLocked(user.provider, user.name)
|
||||
} yield {
|
||||
(JSONFactory400.createUserInfoJSON(user, entitlements, None, isLocked), HttpCode.`200`(cc.callContext))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
getUserLockStatus,
|
||||
implementedInApiVersion,
|
||||
nameOf(getUserLockStatus),
|
||||
"GET",
|
||||
"/users/PROVIDER/USERNAME/lock-status",
|
||||
"Get User Lock Status",
|
||||
s"""
|
||||
|Get User Login Status.
|
||||
|${authenticationRequiredMessage(true)}
|
||||
|
|
||||
|""".stripMargin,
|
||||
EmptyBody,
|
||||
badLoginStatusJson,
|
||||
List(UserNotLoggedIn, UserNotFoundByProviderAndUsername, UserHasMissingRoles, UnknownError),
|
||||
List(apiTagUser, apiTagNewStyle),
|
||||
Some(List(canReadUserLockedStatus))
|
||||
)
|
||||
lazy val getUserLockStatus: OBPEndpoint = {
|
||||
//get private accounts for all banks
|
||||
case "users" ::provider :: username :: "lock-status" :: Nil JsonGet req => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- SS.user
|
||||
_ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canReadUserLockedStatus, callContext)
|
||||
badLoginStatus <- Future {
|
||||
LoginAttempt.getBadLoginStatus(provider, username)
|
||||
} map {
|
||||
unboxFullOrFail(_, callContext, s"$UserNotFoundByProviderAndUsername provider($provider), username($username)", 404)
|
||||
}
|
||||
} yield {
|
||||
(createBadLoginStatusJson(badLoginStatus), HttpCode.`200`(callContext))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resourceDocs += ResourceDoc(
|
||||
unlockUserByProviderAndUsername,
|
||||
implementedInApiVersion,
|
||||
nameOf(unlockUserByProviderAndUsername),
|
||||
"PUT",
|
||||
"/users/PROVIDER/USERNAME/lock-status",
|
||||
"Unlock the user",
|
||||
s"""
|
||||
|Unlock a User.
|
||||
|
|
||||
|(Perhaps the user was locked due to multiple failed login attempts)
|
||||
|
|
||||
|${authenticationRequiredMessage(true)}
|
||||
|
|
||||
|""".stripMargin,
|
||||
EmptyBody,
|
||||
badLoginStatusJson,
|
||||
List(UserNotLoggedIn, UserNotFoundByProviderAndUsername, UserHasMissingRoles, UnknownError),
|
||||
List(apiTagUser, apiTagNewStyle),
|
||||
Some(List(canUnlockUser)))
|
||||
lazy val unlockUserByProviderAndUsername: OBPEndpoint = {
|
||||
//get private accounts for all banks
|
||||
case "users" :: provider :: username :: "lock-status" :: Nil JsonPut req => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- SS.user
|
||||
_ <- NewStyle.function.hasEntitlement("", u.userId, ApiRole.canUnlockUser, callContext)
|
||||
_ <- Future {
|
||||
LoginAttempt.resetBadLoginAttempts(provider, username)
|
||||
}
|
||||
_ <- Future {
|
||||
UserLocksProvider.unlockUser(provider, username)
|
||||
}
|
||||
badLoginStatus <- Future {
|
||||
LoginAttempt.getBadLoginStatus(provider, username)
|
||||
} map {
|
||||
unboxFullOrFail(_, callContext, s"$UserNotFoundByProviderAndUsername provider($provider), username($username)", 404)
|
||||
}
|
||||
} yield {
|
||||
(createBadLoginStatusJson(badLoginStatus), HttpCode.`200`(callContext))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
staticResourceDocs += ResourceDoc(
|
||||
lockUserByProviderAndUsername,
|
||||
implementedInApiVersion,
|
||||
nameOf(lockUserByProviderAndUsername),
|
||||
"POST",
|
||||
"/users/PROVIDER/USERNAME/locks",
|
||||
"Lock the user",
|
||||
s"""
|
||||
|Lock a User.
|
||||
|
|
||||
|${authenticationRequiredMessage(true)}
|
||||
|
|
||||
|""".stripMargin,
|
||||
EmptyBody,
|
||||
userLockStatusJson,
|
||||
List($UserNotLoggedIn, UserNotFoundByProviderAndUsername, UserHasMissingRoles, UnknownError),
|
||||
List(apiTagUser, apiTagNewStyle),
|
||||
Some(List(canLockUser)))
|
||||
lazy val lockUserByProviderAndUsername: OBPEndpoint = {
|
||||
case "users" :: provider :: username :: "locks" :: Nil JsonPost req => {
|
||||
cc =>
|
||||
for {
|
||||
(Full(u), callContext) <- SS.user
|
||||
userLocks <- Future {
|
||||
UserLocksProvider.lockUser(provider, username)
|
||||
} map {
|
||||
unboxFullOrFail(_, callContext, s"$UserNotFoundByProviderAndUsername provider($provider), username($username)", 404)
|
||||
}
|
||||
} yield {
|
||||
(JSONFactory400.createUserLockStatusJson(userLocks), HttpCode.`200`(callContext))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,6 +40,7 @@ import code.api.v3_1_0.APIMethods310
|
||||
import code.api.v4_0_0.APIMethods400
|
||||
import code.api.v5_0_0.{APIMethods500, OBPAPI5_0_0}
|
||||
import code.util.Helper.MdcLoggable
|
||||
import com.github.dwickern.macros.NameOf.nameOf
|
||||
import com.openbankproject.commons.util.{ApiVersion, ApiVersionStatus}
|
||||
import net.liftweb.common.{Box, Full}
|
||||
import net.liftweb.http.{LiftResponse, PlainTextResponse}
|
||||
@ -71,11 +72,18 @@ object OBPAPI5_1_0 extends OBPRestHelper
|
||||
// e.g getEndpoints(Implementations5_0_0) -- List(Implementations5_0_0.genericEndpoint, Implementations5_0_0.root)
|
||||
val endpointsOf5_1_0 = getEndpoints(Implementations5_1_0)
|
||||
|
||||
lazy val bugEndpoints = // these endpoints miss Provider parameter in the URL, we introduce new ones in V510.
|
||||
nameOf(Implementations3_0_0.getUserByUsername) ::
|
||||
nameOf(Implementations3_1_0.getBadLoginStatus) ::
|
||||
nameOf(Implementations3_1_0.unlockUser) ::
|
||||
nameOf(Implementations4_0_0.lockUser) ::
|
||||
Nil
|
||||
|
||||
// if old version ResourceDoc objects have the same name endpoint with new version, omit old version ResourceDoc.
|
||||
def allResourceDocs = collectResourceDocs(
|
||||
OBPAPI5_0_0.allResourceDocs,
|
||||
Implementations5_1_0.resourceDocs
|
||||
)
|
||||
).filterNot(it => it.partialFunctionName.matches(bugEndpoints.mkString("|")))
|
||||
|
||||
// all endpoints
|
||||
private val endpoints: List[OBPEndpoint] = OBPAPI5_0_0.routes ++ endpointsOf5_1_0
|
||||
|
||||
@ -4,6 +4,7 @@ import java.util.Date
|
||||
import java.util.UUID.randomUUID
|
||||
import _root_.akka.http.scaladsl.model.HttpMethod
|
||||
import code.accountholders.{AccountHolders, MapperAccountHolders}
|
||||
import code.api.Constant.localIdentityProvider
|
||||
import code.api.attributedefinition.AttributeDefinition
|
||||
import code.api.cache.Caching
|
||||
import code.api.util.APIUtil.{OBPReturnType, _}
|
||||
@ -1558,7 +1559,7 @@ trait Connector extends MdcLoggable {
|
||||
@deprecated("we create new code.model.dataAccess.AuthUser.updateUserAccountViews for June2017 connector, try to use new instead of this","11 September 2018")
|
||||
def setAccountHolder(owner : String, bankId: BankId, accountId: AccountId, account_owners: List[String]) : Unit = {
|
||||
// if (account_owners.contains(owner)) { // No need for now, fix it later
|
||||
val resourceUserOwner = Users.users.vend.getUserByUserName(owner)
|
||||
val resourceUserOwner = Users.users.vend.getUserByUserName(localIdentityProvider, owner)
|
||||
resourceUserOwner match {
|
||||
case Full(owner) => {
|
||||
if ( ! accountOwnerExists(owner, bankId, accountId).openOrThrowException(attemptedToOpenAnEmptyBox)) {
|
||||
|
||||
@ -10,7 +10,7 @@ import code.accountattribute.AccountAttributeX
|
||||
import code.accountholders.{AccountHolders, MapperAccountHolders}
|
||||
import code.api.BerlinGroup.{AuthenticationType, ScaStatus}
|
||||
import code.api.Constant
|
||||
import code.api.Constant.{INCOMING_SETTLEMENT_ACCOUNT_ID, OUTGOING_SETTLEMENT_ACCOUNT_ID}
|
||||
import code.api.Constant.{INCOMING_SETTLEMENT_ACCOUNT_ID, OUTGOING_SETTLEMENT_ACCOUNT_ID, localIdentityProvider}
|
||||
import code.api.ResourceDocs1_4_0.SwaggerDefinitionsJSON
|
||||
import code.api.attributedefinition.{AttributeDefinition, AttributeDefinitionDI}
|
||||
import code.api.cache.Caching
|
||||
@ -5512,7 +5512,7 @@ object LocalMappedConnector extends Connector with MdcLoggable {
|
||||
@deprecated("we create new code.model.dataAccess.AuthUser.updateUserAccountViews for June2017 connector, try to use new instead of this", "11 September 2018")
|
||||
override def setAccountHolder(owner: String, bankId: BankId, accountId: AccountId, account_owners: List[String]): Unit = {
|
||||
// if (account_owners.contains(owner)) { // No need for now, fix it later
|
||||
val resourceUserOwner = Users.users.vend.getUserByUserName(owner)
|
||||
val resourceUserOwner = Users.users.vend.getUserByUserName(localIdentityProvider, owner)
|
||||
resourceUserOwner match {
|
||||
case Full(owner) => {
|
||||
if (!accountOwnerExists(owner, bankId, accountId).openOrThrowException(attemptedToOpenAnEmptyBox)) {
|
||||
|
||||
@ -102,7 +102,7 @@ trait KafkaMappedConnector_vSept2018 extends Connector with KafkaHelper with Mdc
|
||||
basicUserAuthContexts <- cc.gatewayLoginRequestPayload match {
|
||||
case None =>
|
||||
for{
|
||||
user <- Users.users.vend.getUserByUserName(username) ?~! "getAuthInfoFirstCbsCall: can not get user object here."
|
||||
user <- Users.users.vend.getUserByUserName(provider,username) ?~! "getAuthInfoFirstCbsCall: can not get user object here."
|
||||
userAuthContexts<- UserAuthContextProvider.userAuthContextProvider.vend.getUserAuthContextsBox(user.userId)?~! "getAuthInfoFirstCbsCall: can not get userAuthContexts object here."
|
||||
basicUserAuthContexts = JsonFactory_vSept2018.createBasicUserAuthContextJson(userAuthContexts)
|
||||
} yield
|
||||
|
||||
@ -12,7 +12,7 @@ object LoginAttempt extends MdcLoggable {
|
||||
|
||||
def maxBadLoginAttempts = APIUtil.getPropsValue("max.bad.login.attempts") openOr "5"
|
||||
|
||||
def incrementBadLoginAttempts(username: String, provider: String): Unit = {
|
||||
def incrementBadLoginAttempts(provider: String, username: String): Unit = {
|
||||
username.isEmpty() match {
|
||||
case true => // Not a valid case. GitLab issue 389
|
||||
logger.warn(s"Username is empty: incrementBadLoginAttempts(username=$username, provider=$provider")
|
||||
@ -20,7 +20,10 @@ object LoginAttempt extends MdcLoggable {
|
||||
logger.debug(s"Hello from incrementBadLoginAttempts with $username")
|
||||
|
||||
// Find badLoginAttempt record if one exists for a user
|
||||
MappedBadLoginAttempt.find(By(MappedBadLoginAttempt.mUsername, username)) match {
|
||||
MappedBadLoginAttempt.find(
|
||||
By(MappedBadLoginAttempt.Provider, provider),
|
||||
By(MappedBadLoginAttempt.mUsername, username)
|
||||
) match {
|
||||
// If it exits update the date and increment
|
||||
case Full(loginAttempt) =>
|
||||
|
||||
@ -44,17 +47,23 @@ object LoginAttempt extends MdcLoggable {
|
||||
}
|
||||
}
|
||||
|
||||
def getBadLoginStatus(username: String): Box[BadLoginAttempt] = {
|
||||
MappedBadLoginAttempt.find(By(MappedBadLoginAttempt.mUsername, username))
|
||||
def getBadLoginStatus(provider: String, username: String): Box[BadLoginAttempt] = {
|
||||
MappedBadLoginAttempt.find(
|
||||
By(MappedBadLoginAttempt.Provider, provider),
|
||||
By(MappedBadLoginAttempt.mUsername, username)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* check the bad login attempts, if it exceed the "max.bad.login.attempts"(in default.props), it return false.
|
||||
*/
|
||||
def userIsLocked(username: String): Boolean = {
|
||||
def userIsLocked(provider: String, username: String): Boolean = {
|
||||
|
||||
val result : Boolean = MappedBadLoginAttempt.find(By(MappedBadLoginAttempt.mUsername, username)) match {
|
||||
case Empty => UserLocksProvider.isLocked(username)
|
||||
val result : Boolean = MappedBadLoginAttempt.find(
|
||||
By(MappedBadLoginAttempt.Provider, provider),
|
||||
By(MappedBadLoginAttempt.mUsername, username)
|
||||
) match {
|
||||
case Empty => UserLocksProvider.isLocked(provider, username)
|
||||
case Full(loginAttempt) => loginAttempt.badAttemptsSinceLastSuccessOrReset > maxBadLoginAttempts.toInt match {
|
||||
case true => true
|
||||
case false => false
|
||||
@ -67,9 +76,12 @@ object LoginAttempt extends MdcLoggable {
|
||||
|
||||
}
|
||||
|
||||
def resetBadLoginAttempts(username: String): Unit = {
|
||||
def resetBadLoginAttempts(provider: String, username: String): Unit = {
|
||||
|
||||
MappedBadLoginAttempt.find(By(MappedBadLoginAttempt.mUsername, username)) match {
|
||||
MappedBadLoginAttempt.find(
|
||||
By(MappedBadLoginAttempt.Provider, provider),
|
||||
By(MappedBadLoginAttempt.mUsername, username)
|
||||
) match {
|
||||
case Full(loginAttempt) =>
|
||||
loginAttempt.mLastFailureDate(now).mBadAttemptsSinceLastSuccessOrReset(0).save
|
||||
case _ =>
|
||||
|
||||
@ -21,7 +21,7 @@ class MappedBadLoginAttempt extends BadLoginAttempt with LongKeyedMapper[MappedB
|
||||
}
|
||||
|
||||
object MappedBadLoginAttempt extends MappedBadLoginAttempt with LongKeyedMetaMapper[MappedBadLoginAttempt] {
|
||||
override def dbIndexes = UniqueIndex(mUsername) :: super.dbIndexes
|
||||
override def dbIndexes = UniqueIndex(Provider,mUsername) :: super.dbIndexes
|
||||
}
|
||||
|
||||
trait BadLoginAttempt {
|
||||
|
||||
@ -338,7 +338,7 @@ case class BankAccountExtended(val bankAccount: BankAccount) extends MdcLoggable
|
||||
final def revokeAllAccountAccess(user : User, otherUserProvider : String, otherUserIdGivenByProvider: String) : Box[Boolean] = {
|
||||
if(canRevokeAccessToViewCommon(bankId, accountId, user))
|
||||
for{
|
||||
otherUser <- UserX.findByProviderId(otherUserProvider, otherUserIdGivenByProvider) ?~ UserNotFoundByUsername
|
||||
otherUser <- UserX.findByProviderId(otherUserProvider, otherUserIdGivenByProvider) ?~ UserNotFoundByProviderAndUsername
|
||||
isRevoked <- Views.views.vend.revokeAllAccountAccess(bankId, accountId, otherUser)
|
||||
} yield isRevoked
|
||||
else
|
||||
|
||||
@ -142,8 +142,8 @@ object UserX {
|
||||
usr
|
||||
}
|
||||
|
||||
def findByUserName(userName: String) = {
|
||||
Users.users.vend.getUserByUserName(userName)
|
||||
def findByUserName(provider: String, userName: String) = {
|
||||
Users.users.vend.getUserByUserName(provider, userName)
|
||||
}
|
||||
|
||||
def findByEmail(email: String) = {
|
||||
@ -165,8 +165,8 @@ object UserX {
|
||||
Users.users.vend.saveResourceUser(ru)
|
||||
}
|
||||
|
||||
def getOrCreateDauthResourceUser(username: String, provider: String) = {
|
||||
findByUserName(username).or( //first try to find the user by userId
|
||||
def getOrCreateDauthResourceUser(provider: String, username: String) = {
|
||||
findByUserName(provider, username).or( //first try to find the user by userId
|
||||
Users.users.vend.createResourceUser( // Otherwise create a new user
|
||||
provider = provider,
|
||||
providerId = Some(username),
|
||||
|
||||
@ -348,8 +348,8 @@ class AuthUser extends MegaProtoUser[AuthUser] with CreatedUpdated with MdcLogga
|
||||
}
|
||||
}
|
||||
|
||||
def getResourceUserByUsername(username: String) : Box[User] = {
|
||||
Users.users.vend.getUserByUserName(username)
|
||||
def getResourceUserByUsername(provider: String, username: String) : Box[User] = {
|
||||
Users.users.vend.getUserByUserName(provider, username)
|
||||
}
|
||||
|
||||
override def save(): Boolean = {
|
||||
@ -469,10 +469,11 @@ import net.liftweb.util.Helpers._
|
||||
val authorization: Box[String] = S.request.map(_.header("Authorization")).flatten
|
||||
val directLogin: Box[String] = S.request.map(_.header("DirectLogin")).flatten
|
||||
for {
|
||||
resourceUser <- if (AuthUser.currentUser.isDefined)
|
||||
//AuthUser.currentUser.get.user.foreign // this will be issue when the resource user is in remote side
|
||||
Users.users.vend.getUserByUserName(AuthUser.currentUser.openOrThrowException(ErrorMessages.attemptedToOpenAnEmptyBox).username.get)
|
||||
else if (directLogin.isDefined) // Direct Login
|
||||
resourceUser <- if (AuthUser.currentUser.isDefined){
|
||||
//AuthUser.currentUser.get.user.foreign // this will be issue when the resource user is in remote side {
|
||||
val user = AuthUser.currentUser.openOrThrowException(ErrorMessages.attemptedToOpenAnEmptyBox)
|
||||
Users.users.vend.getUserByUserName(user.provider.get, user.username.get)
|
||||
}else if (directLogin.isDefined) // Direct Login
|
||||
DirectLogin.getUser
|
||||
else if (hasDirectLoginHeader(authorization)) // Direct Login Deprecated
|
||||
DirectLogin.getUser
|
||||
@ -619,7 +620,7 @@ import net.liftweb.util.Helpers._
|
||||
}
|
||||
|
||||
def grantDefaultEntitlementsToAuthUser(user: TheUserType) = {
|
||||
tryo{getResourceUserByUsername(user.username.get).head.userId} match {
|
||||
tryo{getResourceUserByUsername(user.getProvider(), user.username.get).head.userId} match {
|
||||
case Full(userId)=>APIUtil.grantDefaultEntitlementsToNewUser(userId)
|
||||
case _ => logger.error("Can not getResourceUserByUsername here, so it breaks the grantDefaultEntitlementsToNewUser process.")
|
||||
}
|
||||
@ -810,39 +811,39 @@ import net.liftweb.util.Helpers._
|
||||
if (
|
||||
user.validated_? &&
|
||||
// User is NOT locked AND the password is good
|
||||
! LoginAttempt.userIsLocked(username) &&
|
||||
! LoginAttempt.userIsLocked(user.getProvider(), username) &&
|
||||
user.testPassword(Full(password)))
|
||||
{
|
||||
// We logged in correctly, so reset badLoginAttempts counter (if it exists)
|
||||
LoginAttempt.resetBadLoginAttempts(username)
|
||||
LoginAttempt.resetBadLoginAttempts(user.getProvider(), username)
|
||||
Full(user.user.get) // Return the user.
|
||||
}
|
||||
// User is unlocked AND password is bad
|
||||
else if (
|
||||
user.validated_? &&
|
||||
! LoginAttempt.userIsLocked(username) &&
|
||||
! LoginAttempt.userIsLocked(user.getProvider(), username) &&
|
||||
! user.testPassword(Full(password))
|
||||
) {
|
||||
LoginAttempt.incrementBadLoginAttempts(username, user.getProvider())
|
||||
LoginAttempt.incrementBadLoginAttempts(user.getProvider(), username)
|
||||
Empty
|
||||
}
|
||||
// User is locked
|
||||
else if (LoginAttempt.userIsLocked(username))
|
||||
else if (LoginAttempt.userIsLocked(user.getProvider(), username))
|
||||
{
|
||||
LoginAttempt.incrementBadLoginAttempts(username, user.getProvider())
|
||||
LoginAttempt.incrementBadLoginAttempts(user.getProvider(), username)
|
||||
logger.info(ErrorMessages.UsernameHasBeenLocked)
|
||||
//TODO need to fix, use Failure instead, it is used to show the error message to the GUI
|
||||
Full(usernameLockedStateCode)
|
||||
}
|
||||
else {
|
||||
// Nothing worked, so just increment bad login attempts
|
||||
LoginAttempt.incrementBadLoginAttempts(username, user.getProvider())
|
||||
LoginAttempt.incrementBadLoginAttempts(user.getProvider(), username)
|
||||
Empty
|
||||
}
|
||||
// We have a user from an external provider.
|
||||
case Full(user) if (user.getProvider() != Constant.localIdentityProvider) =>
|
||||
APIUtil.getPropsAsBoolValue("connector.user.authentication", false) match {
|
||||
case true if !LoginAttempt.userIsLocked(username) =>
|
||||
case true if !LoginAttempt.userIsLocked(user.getProvider(), username) =>
|
||||
val userId =
|
||||
for {
|
||||
authUser <- checkExternalUserViaConnector(username, password)
|
||||
@ -850,22 +851,22 @@ import net.liftweb.util.Helpers._
|
||||
authUser.user
|
||||
}
|
||||
} yield {
|
||||
LoginAttempt.resetBadLoginAttempts(username)
|
||||
LoginAttempt.resetBadLoginAttempts(user.getProvider(), username)
|
||||
resourceUser.get
|
||||
}
|
||||
userId match {
|
||||
case Full(l: Long) => Full(l)
|
||||
case _ =>
|
||||
LoginAttempt.incrementBadLoginAttempts(username, user.getProvider())
|
||||
LoginAttempt.incrementBadLoginAttempts(user.getProvider(), username)
|
||||
Empty
|
||||
}
|
||||
case false =>
|
||||
LoginAttempt.incrementBadLoginAttempts(username, user.getProvider())
|
||||
LoginAttempt.incrementBadLoginAttempts(user.getProvider(), username)
|
||||
Empty
|
||||
}
|
||||
// Everything else.
|
||||
case _ =>
|
||||
LoginAttempt.incrementBadLoginAttempts(username, user.foreign.map(_.provider).getOrElse(Constant.HostName))
|
||||
LoginAttempt.incrementBadLoginAttempts(user.foreign.map(_.provider).getOrElse(Constant.HostName), username)
|
||||
Empty
|
||||
}
|
||||
}
|
||||
@ -1059,12 +1060,12 @@ def restoreSomeSessions(): Unit = {
|
||||
}
|
||||
|
||||
def obpUserIsValidatedAndNotLocked(usernameFromGui: String, user: AuthUser) = {
|
||||
user.validated_? && !LoginAttempt.userIsLocked(usernameFromGui) &&
|
||||
user.validated_? && !LoginAttempt.userIsLocked(user.getProvider(), usernameFromGui) &&
|
||||
isObpProvider(user)
|
||||
}
|
||||
|
||||
def externalUserIsValidatedAndNotLocked(usernameFromGui: String, user: AuthUser) = {
|
||||
user.validated_? && !LoginAttempt.userIsLocked(usernameFromGui) &&
|
||||
user.validated_? && !LoginAttempt.userIsLocked(user.getProvider(), usernameFromGui) &&
|
||||
!isObpProvider(user)
|
||||
}
|
||||
|
||||
@ -1090,7 +1091,7 @@ def restoreSomeSessions(): Unit = {
|
||||
case Full(user) if obpUserIsValidatedAndNotLocked(usernameFromGui, user) =>
|
||||
if(user.testPassword(Full(passwordFromGui))) { // if User is NOT locked and password is good
|
||||
// Reset any bad attempt
|
||||
LoginAttempt.resetBadLoginAttempts(usernameFromGui)
|
||||
LoginAttempt.resetBadLoginAttempts(user.getProvider(), usernameFromGui)
|
||||
val preLoginState = capturePreLoginState()
|
||||
// User init actions
|
||||
AfterApiAuth.innerLoginUserInitAction(Full(user))
|
||||
@ -1098,13 +1099,13 @@ def restoreSomeSessions(): Unit = {
|
||||
val redirect = redirectUri()
|
||||
checkInternalRedirectAndLogUserIn(preLoginState, redirect, user)
|
||||
} else { // If user is NOT locked AND password is wrong => increment bad login attempt counter.
|
||||
LoginAttempt.incrementBadLoginAttempts(usernameFromGui, user.getProvider())
|
||||
LoginAttempt.incrementBadLoginAttempts(user.getProvider(),usernameFromGui)
|
||||
S.error(Helper.i18n("invalid.login.credentials"))
|
||||
}
|
||||
|
||||
// If user is locked, send the error to GUI
|
||||
case Full(user) if LoginAttempt.userIsLocked(usernameFromGui) =>
|
||||
LoginAttempt.incrementBadLoginAttempts(usernameFromGui, user.getProvider())
|
||||
case Full(user) if LoginAttempt.userIsLocked(user.getProvider(), usernameFromGui) =>
|
||||
LoginAttempt.incrementBadLoginAttempts(user.getProvider(),usernameFromGui)
|
||||
S.error(S.?(ErrorMessages.UsernameHasBeenLocked))
|
||||
|
||||
// Check if user came from kafka/obpjvm/stored_procedure and
|
||||
@ -1112,13 +1113,13 @@ def restoreSomeSessions(): Unit = {
|
||||
// from connector in case they changed on the south-side
|
||||
case Full(user) if externalUserIsValidatedAndNotLocked(usernameFromGui, user) && testExternalPassword(usernameFromGui, passwordFromGui) =>
|
||||
// Reset any bad attempts
|
||||
LoginAttempt.resetBadLoginAttempts(usernameFromGui)
|
||||
LoginAttempt.resetBadLoginAttempts(user.getProvider(), usernameFromGui)
|
||||
val preLoginState = capturePreLoginState()
|
||||
logger.info("login redirect: " + loginRedirect.get)
|
||||
val redirect = redirectUri()
|
||||
//This method is used for connector = kafka* || obpjvm*
|
||||
//It will update the views and createAccountHolder ....
|
||||
registeredUserHelper(user.username.get)
|
||||
registeredUserHelper(user.getProvider(),user.username.get)
|
||||
// User init actions
|
||||
AfterApiAuth.innerLoginUserInitAction(Full(user))
|
||||
checkInternalRedirectAndLogUserIn(preLoginState, redirect, user)
|
||||
@ -1132,12 +1133,12 @@ def restoreSomeSessions(): Unit = {
|
||||
val redirect = redirectUri()
|
||||
externalUserHelper(usernameFromGui, passwordFromGui) match {
|
||||
case Full(user: AuthUser) =>
|
||||
LoginAttempt.resetBadLoginAttempts(usernameFromGui)
|
||||
LoginAttempt.resetBadLoginAttempts(user.getProvider(), usernameFromGui)
|
||||
// User init actions
|
||||
AfterApiAuth.innerLoginUserInitAction(Full(user))
|
||||
checkInternalRedirectAndLogUserIn(preLoginState, redirect, user)
|
||||
case _ =>
|
||||
LoginAttempt.incrementBadLoginAttempts(username.get, user.foreign.map(_.provider).getOrElse(Constant.HostName))
|
||||
LoginAttempt.incrementBadLoginAttempts(user.foreign.map(_.provider).getOrElse(Constant.HostName), username.get)
|
||||
Empty
|
||||
S.error(Helper.i18n("invalid.login.credentials"))
|
||||
}
|
||||
@ -1146,7 +1147,7 @@ def restoreSomeSessions(): Unit = {
|
||||
case Empty =>
|
||||
S.error(Helper.i18n("invalid.login.credentials"))
|
||||
case _ =>
|
||||
LoginAttempt.incrementBadLoginAttempts(usernameFromGui, user.foreign.map(_.provider).getOrElse(Constant.HostName))
|
||||
LoginAttempt.incrementBadLoginAttempts(user.foreign.map(_.provider).getOrElse(Constant.HostName), usernameFromGui)
|
||||
S.error(S.?(ErrorMessages.UnexpectedErrorDuringLogin)) // Note we hit this if user has not clicked email validation link
|
||||
}
|
||||
}
|
||||
@ -1203,14 +1204,14 @@ def restoreSomeSessions(): Unit = {
|
||||
if (connector.startsWith("kafka") ) {
|
||||
for {
|
||||
user <- getUserFromConnector(name, password)
|
||||
u <- Users.users.vend.getUserByUserName(name)
|
||||
u <- Users.users.vend.getUserByUserName(user.getProvider(), name)
|
||||
} yield {
|
||||
user
|
||||
}
|
||||
} else {
|
||||
for {
|
||||
user <- checkExternalUserViaConnector(name, password)
|
||||
u <- Users.users.vend.getUserByUserName(name)
|
||||
u <- Users.users.vend.getUserByUserName(user.getProvider(), name)
|
||||
} yield {
|
||||
user
|
||||
}
|
||||
@ -1221,10 +1222,10 @@ def restoreSomeSessions(): Unit = {
|
||||
/**
|
||||
* This method will update the views and createAccountHolder ....
|
||||
*/
|
||||
def registeredUserHelper(username: String) = {
|
||||
def registeredUserHelper(provider: String, username: String) = {
|
||||
if (connector.startsWith("kafka")) {
|
||||
for {
|
||||
u <- Users.users.vend.getUserByUserName(username)
|
||||
u <- Users.users.vend.getUserByUserName(provider, username)
|
||||
} yield {
|
||||
refreshUser(u, None)
|
||||
}
|
||||
|
||||
@ -50,12 +50,12 @@ object RemotedataUsers extends ObpActorInit with Users {
|
||||
def getUsersByUserIdsFuture(userIds : List[String]) : Future[List[User]] =
|
||||
(actor ? cc.getUsersByUserIdsFuture(userIds)).mapTo[List[User]]
|
||||
|
||||
def getUserByUserName(userName : String) : Box[ResourceUser] = getValueFromFuture(
|
||||
(actor ? cc.getUserByUserName(userName)).mapTo[Box[ResourceUser]]
|
||||
def getUserByUserName(provider : String, userName : String) : Box[ResourceUser] = getValueFromFuture(
|
||||
(actor ? cc.getUserByUserName(provider, userName)).mapTo[Box[ResourceUser]]
|
||||
)
|
||||
|
||||
def getUserByUserNameFuture(userName : String) : Future[Box[User]] =
|
||||
(actor ? cc.getUserByUserNameFuture(userName)).mapTo[Box[User]]
|
||||
def getUserByProviderAndUsernameFuture(provider: String, username: String): Future[Box[User]] =
|
||||
(actor ? cc.getUserByUserNameFuture(provider, username)).mapTo[Box[User]]
|
||||
|
||||
def getUserByEmail(email : String) : Box[List[ResourceUser]] = getValueFromFuture(
|
||||
(actor ? cc.getUserByEmail(email)).mapTo[Box[List[ResourceUser]]]
|
||||
|
||||
@ -57,13 +57,13 @@ class RemotedataUsersActor extends Actor with ObpActorHelper with MdcLoggable {
|
||||
logger.debug("getUsersByUserIdsFuture(" + userIds +")")
|
||||
sender ! (mapper.getUsersByUserIds(userIds))
|
||||
|
||||
case cc.getUserByUserName(userName: String) =>
|
||||
logger.debug("getUserByUserName(" + userName +")")
|
||||
sender ! (mapper.getUserByUserName(userName))
|
||||
case cc.getUserByUserName(provider: String, userName: String) =>
|
||||
logger.debug("getUserByUserName("+provider + userName +")")
|
||||
sender ! (mapper.getUserByUserName(provider, userName))
|
||||
|
||||
case cc.getUserByUserNameFuture(userName: String) =>
|
||||
logger.debug("getUserByUserNameFuture(" + userName +")")
|
||||
sender ! (mapper.getUserByUserName(userName))
|
||||
case cc.getUserByUserNameFuture(provider: String, userName: String) =>
|
||||
logger.debug("getUserByUserNameFuture("+provider + userName +")")
|
||||
sender ! (mapper.getUserByUserName(provider, userName))
|
||||
|
||||
case cc.getUserByEmail(email: String) =>
|
||||
logger.debug("getUserByEmail(" + email +")")
|
||||
|
||||
@ -2,9 +2,8 @@ package code.sandbox
|
||||
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.UUID
|
||||
|
||||
import code.accountholders.AccountHolders
|
||||
import code.api.Constant.{SYSTEM_ACCOUNTANT_VIEW_ID, SYSTEM_AUDITOR_VIEW_ID, SYSTEM_FIREHOSE_VIEW_ID, SYSTEM_OWNER_VIEW_ID}
|
||||
import code.api.Constant.{SYSTEM_ACCOUNTANT_VIEW_ID, SYSTEM_AUDITOR_VIEW_ID, SYSTEM_FIREHOSE_VIEW_ID, SYSTEM_OWNER_VIEW_ID, localIdentityProvider}
|
||||
import code.api.util.APIUtil._
|
||||
import code.api.util.{APIUtil, ApiPropsWithAlias, ErrorMessages}
|
||||
import code.bankconnectors.Connector
|
||||
@ -124,7 +123,7 @@ trait OBPDataImport extends MdcLoggable {
|
||||
protected def createSaveableUser(u : SandboxUserImport) : Box[Saveable[ResourceUser]]
|
||||
|
||||
protected def createUsers(toImport : List[SandboxUserImport]) : Box[List[Saveable[ResourceUser]]] = {
|
||||
val existingResourceUsers = toImport.flatMap(u => Users.users.vend.getUserByUserName(u.user_name))
|
||||
val existingResourceUsers = toImport.flatMap(u => Users.users.vend.getUserByUserName(localIdentityProvider, u.user_name))
|
||||
val allUsernames = toImport.map(_.user_name)
|
||||
val duplicateUsernames = allUsernames diff allUsernames.distinct
|
||||
|
||||
|
||||
@ -28,8 +28,8 @@ package code.snippet
|
||||
|
||||
import java.time.{Duration, ZoneId, ZoneOffset, ZonedDateTime}
|
||||
import java.util.Date
|
||||
|
||||
import code.api.Constant
|
||||
import code.api.Constant.localIdentityProvider
|
||||
import code.api.util.{APIUtil, SecureRandomUtil}
|
||||
import code.model.dataAccess.{AuthUser, ResourceUser}
|
||||
import code.users
|
||||
@ -99,7 +99,7 @@ class UserInvitation extends MdcLoggable {
|
||||
else if(userInvitation.map(_.status != "CREATED").getOrElse(false)) showErrorsForStatus()
|
||||
else if(timeDifference.abs.getSeconds > ttl) showErrorsForTtl()
|
||||
else if(AuthUser.currentUser.isDefined) showErrorYouMustBeLoggedOff()
|
||||
else if(Users.users.vend.getUserByUserName(usernameVar.is).isDefined) showErrorsForUsername()
|
||||
else if(Users.users.vend.getUserByUserName(localIdentityProvider, usernameVar.is).isDefined) showErrorsForUsername()
|
||||
else if(privacyCheckboxVar.is == false) showErrorsForPrivacyConditions()
|
||||
else if(termsCheckboxVar.is == false) showErrorsForTermsAndConditions()
|
||||
else if(personalDataCollectionConsentCountryWaiverList.exists(_.toLowerCase == countryVar.is.toLowerCase) == false && consentForCollectingCheckboxVar.is == false) showErrorsForConsentForCollectingPersonalData()
|
||||
|
||||
@ -7,8 +7,8 @@ import net.liftweb.mapper.By
|
||||
import net.liftweb.util.Helpers._
|
||||
|
||||
object UserLocksProvider extends MdcLoggable {
|
||||
def isLocked(username: String): Boolean = {
|
||||
Users.users.vend.getUserByUserName(username) match {
|
||||
def isLocked(provider: String, username: String): Boolean = {
|
||||
Users.users.vend.getUserByUserName(provider, username) match {
|
||||
case Full(user) =>
|
||||
UserLocks.find(By(UserLocks.UserId, user.userId)) match {
|
||||
case Full(_) => true
|
||||
@ -17,8 +17,8 @@ object UserLocksProvider extends MdcLoggable {
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
def lockUser(username: String): Box[UserLocks] = {
|
||||
Users.users.vend.getUserByUserName(username) match {
|
||||
def lockUser(provider: String, username: String): Box[UserLocks] = {
|
||||
Users.users.vend.getUserByUserName(provider, username) match {
|
||||
case Full(user) =>
|
||||
UserLocks.find(By(UserLocks.UserId, user.userId)) match {
|
||||
case Full(userLocks) =>
|
||||
@ -40,8 +40,8 @@ object UserLocksProvider extends MdcLoggable {
|
||||
Empty
|
||||
}
|
||||
}
|
||||
def unlockUser(username: String): Box[Boolean] = {
|
||||
Users.users.vend.getUserByUserName(username) match {
|
||||
def unlockUser(provider: String, username: String): Box[Boolean] = {
|
||||
Users.users.vend.getUserByUserName(provider, username) match {
|
||||
case Full(user) =>
|
||||
UserLocks.find(By(UserLocks.UserId, user.userId)) match {
|
||||
case Full(userLocks) => Some(userLocks.delete_!)
|
||||
|
||||
@ -92,13 +92,16 @@ object LiftUsers extends Users with MdcLoggable{
|
||||
Future(getUsersByUserIds(userIds))
|
||||
}
|
||||
|
||||
override def getUserByUserName(userName: String): Box[User] = {
|
||||
ResourceUser.find(By(ResourceUser.name_, userName))
|
||||
override def getUserByUserName(provider : String, userName: String): Box[User] = {
|
||||
ResourceUser.find(
|
||||
By(ResourceUser.provider_, provider),
|
||||
By(ResourceUser.name_, userName)
|
||||
)
|
||||
}
|
||||
|
||||
override def getUserByUserNameFuture(userName: String): Future[Box[User]] = {
|
||||
override def getUserByProviderAndUsernameFuture(provider: String, username: String): Future[Box[User]] = {
|
||||
Future {
|
||||
getUserByUserName(userName)
|
||||
getUserByUserName(provider, username)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -43,8 +43,8 @@ trait Users {
|
||||
def getUsersByUserIdsFuture(userIds : List[String]) : Future[List[User]]
|
||||
|
||||
// find ResourceUser by Resourceuser user name
|
||||
def getUserByUserName(userName: String) : Box[User]
|
||||
def getUserByUserNameFuture(userName: String) : Future[Box[User]]
|
||||
def getUserByUserName(provider: String, userName: String) : Box[User]
|
||||
def getUserByProviderAndUsernameFuture(provider: String, username: String): Future[Box[User]]
|
||||
|
||||
def getUserByEmail(email: String) : Box[List[ResourceUser]]
|
||||
def getUserByEmailFuture(email: String) : Future[List[(ResourceUser, Box[List[Entitlement]])]]
|
||||
@ -87,8 +87,8 @@ class RemotedataUsersCaseClasses {
|
||||
case class getUserByUserId(userId : String)
|
||||
case class getUserByUserIdFuture(userId : String)
|
||||
case class getUsersByUserIdsFuture(userId : List[String])
|
||||
case class getUserByUserName(userName : String)
|
||||
case class getUserByUserNameFuture(userName : String)
|
||||
case class getUserByUserName(provider : String, userName : String)
|
||||
case class getUserByUserNameFuture(provider : String, userName : String)
|
||||
case class getUserByEmail(email : String)
|
||||
case class getUserByEmailFuture(email : String)
|
||||
case class getUsersByEmail(email : String)
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package code.api
|
||||
|
||||
import code.api.Constant.localIdentityProvider
|
||||
import code.api.util.ErrorMessages
|
||||
import code.api.util.ErrorMessages._
|
||||
import code.api.v2_0_0.OBPAPI2_0_0.Implementations2_0_0
|
||||
@ -184,7 +185,7 @@ class DirectLoginTest extends ServerSetup with BeforeAndAfter {
|
||||
assertResponse(response, ErrorMessages.UsernameHasBeenLocked)
|
||||
|
||||
Then("We unlock the username")
|
||||
LoginAttempt.resetBadLoginAttempts(USERNAME)
|
||||
LoginAttempt.resetBadLoginAttempts(localIdentityProvider, USERNAME)
|
||||
}
|
||||
|
||||
scenario("Consumer API key is disabled") {
|
||||
@ -431,7 +432,7 @@ class DirectLoginTest extends ServerSetup with BeforeAndAfter {
|
||||
lazy val validHeadersWithToken = List(accessControlOriginHeader, headerWithToken)
|
||||
|
||||
// Lock the user in order to test functionality
|
||||
UserLocksProvider.lockUser(username)
|
||||
UserLocksProvider.lockUser(localIdentityProvider, username)
|
||||
|
||||
When("when we use the token to get current user and it should NOT work due to locked user - New Style")
|
||||
lazy val requestCurrentUserNewStyle = baseRequest / "obp" / "v3.0.0" / "users" / "current"
|
||||
|
||||
@ -346,7 +346,8 @@ class OAuthTest extends ServerSetup {
|
||||
verifier.asInstanceOf[Failure].msg.contains(ErrorMessages.UsernameHasBeenLocked) should equal (true)
|
||||
|
||||
Then("We unlock the username")
|
||||
LoginAttempt.resetBadLoginAttempts(user1.username.get)
|
||||
LoginAttempt.resetBadLoginAttempts(user1.getProvider(), user1.username.get)
|
||||
|
||||
setPropsValues("max.bad.login.attempts"-> "5")
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@ package code.api.v4_0_0
|
||||
|
||||
import code.api.util.APIUtil.OAuth._
|
||||
import code.api.util.ApiRole.CanLockUser
|
||||
import code.api.util.ErrorMessages.{UserHasMissingRoles, UserNotFoundByUsername, UserNotLoggedIn}
|
||||
import code.api.util.ErrorMessages.{UserHasMissingRoles, UserNotFoundByProviderAndUsername, UserNotLoggedIn}
|
||||
import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
|
||||
import code.entitlement.Entitlement
|
||||
import com.github.dwickern.macros.NameOf.nameOf
|
||||
@ -51,7 +51,7 @@ class LockUserTest extends V400ServerSetup {
|
||||
val response400 = makePostRequest(request400, "")
|
||||
Then("We should get a 404")
|
||||
response400.code should equal(404)
|
||||
response400.body.extract[ErrorMessage].message should be (s"$UserNotFoundByUsername($username)")
|
||||
response400.body.extract[ErrorMessage].message should be (s"$UserNotFoundByProviderAndUsername($username)")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -30,7 +30,7 @@ import okhttp3.{OkHttpClient, Request}
|
||||
|
||||
class IndexPageTest extends V510ServerSetup {
|
||||
|
||||
/**
|
||||
/**d
|
||||
* Test tags
|
||||
* Example: To run tests with tag "getPermissions":
|
||||
* mvn test -D tagsToInclude
|
||||
|
||||
186
obp-api/src/test/scala/code/api/v5_1_0/LockUserTest.scala
Normal file
186
obp-api/src/test/scala/code/api/v5_1_0/LockUserTest.scala
Normal file
@ -0,0 +1,186 @@
|
||||
package code.api.v5_1_0
|
||||
|
||||
import code.api.Constant.localIdentityProvider
|
||||
import code.api.util.APIUtil.OAuth
|
||||
import code.api.util.APIUtil.OAuth._
|
||||
import code.api.util.ApiRole.{CanLockUser, CanReadUserLockedStatus, CanUnlockUser}
|
||||
import code.api.util.ErrorMessages.{UserHasMissingRoles, UserNotFoundByProviderAndUsername, UserNotLoggedIn, UsernameHasBeenLocked}
|
||||
import code.api.v3_0_0.UserJsonV300
|
||||
import code.api.v3_1_0.BadLoginStatusJson
|
||||
import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
|
||||
import code.entitlement.Entitlement
|
||||
import code.loginattempts.LoginAttempt
|
||||
import com.github.dwickern.macros.NameOf.nameOf
|
||||
import com.openbankproject.commons.model.ErrorMessage
|
||||
import com.openbankproject.commons.util.ApiVersion
|
||||
import org.scalatest.Tag
|
||||
|
||||
class LockUserTest extends V510ServerSetup {
|
||||
/**
|
||||
* Test tags
|
||||
* Example: To run tests with tag "getPermissions":
|
||||
* mvn test -D tagsToInclude
|
||||
*
|
||||
* This is made possible by the scalatest maven plugin
|
||||
*/
|
||||
object VersionOfApi extends Tag(ApiVersion.v5_1_0.toString)
|
||||
object ApiEndpoint1 extends Tag(nameOf(Implementations5_1_0.lockUserByProviderAndUsername))
|
||||
object ApiEndpoint2 extends Tag(nameOf(Implementations5_1_0.getUserLockStatus))
|
||||
object ApiEndpoint3 extends Tag(nameOf(Implementations5_1_0.unlockUserByProviderAndUsername))
|
||||
|
||||
|
||||
feature(s"test $ApiEndpoint1,$ApiEndpoint2, $ApiEndpoint3, version $VersionOfApi - Unauthorized access") {
|
||||
scenario(s"We will call the $ApiEndpoint1 without user credentials", ApiEndpoint1, VersionOfApi) {
|
||||
When("We make a request v5.1.0")
|
||||
val request = (v5_1_0_Request / "users"/"PROVIDER" / "USERNAME" / "locks").POST
|
||||
val response = makePostRequest(request, "")
|
||||
Then("We should get a 401")
|
||||
response.code should equal(401)
|
||||
response.body.extract[ErrorMessage].message should equal(UserNotLoggedIn)
|
||||
}
|
||||
scenario(s"We will call the $ApiEndpoint2 without user credentials", ApiEndpoint2, VersionOfApi) {
|
||||
When("We make a request v5.1.0")
|
||||
val request = (v5_1_0_Request / "users" / "PROVIDER" / "USERNAME" / "lock-status").GET
|
||||
val response = makeGetRequest(request)
|
||||
Then("We should get a 401")
|
||||
response.code should equal(401)
|
||||
response.body.extract[ErrorMessage].message should equal(UserNotLoggedIn)
|
||||
}
|
||||
scenario(s"We will call the $ApiEndpoint3 without user credentials", ApiEndpoint3, VersionOfApi) {
|
||||
When("We make a request v5.1.0")
|
||||
val request = (v5_1_0_Request / "users" / "PROVIDER" / "USERNAME" / "lock-status").PUT
|
||||
val response = makePutRequest(request, "")
|
||||
Then("We should get a 401")
|
||||
response.code should equal(401)
|
||||
response.body.extract[ErrorMessage].message should equal(UserNotLoggedIn)
|
||||
}
|
||||
}
|
||||
|
||||
feature(s"test $ApiEndpoint1,$ApiEndpoint2, $ApiEndpoint3, version $VersionOfApi - Missing roles") {
|
||||
scenario(s"We will call the $ApiEndpoint1 without user credentials", ApiEndpoint1, VersionOfApi) {
|
||||
When("We make a request v5.1.0")
|
||||
val request = (v5_1_0_Request /"users" /"PROVIDER" / "USERNAME" / "locks").POST <@(user1)
|
||||
val response = makePostRequest(request, "")
|
||||
Then("error should be " + UserHasMissingRoles + CanLockUser)
|
||||
response.code should equal(403)
|
||||
response.body.extract[ErrorMessage].message should be (UserHasMissingRoles + CanLockUser)
|
||||
}
|
||||
scenario(s"We will call the $ApiEndpoint2 without user credentials", ApiEndpoint2, VersionOfApi) {
|
||||
When("We make a request v5.1.0")
|
||||
val request = (v5_1_0_Request / "users" /"PROVIDER" / "USERNAME" / "lock-status").GET <@(user1)
|
||||
val response = makeGetRequest(request)
|
||||
Then("error should be " + UserHasMissingRoles + CanReadUserLockedStatus)
|
||||
response.code should equal(403)
|
||||
response.body.extract[ErrorMessage].message should be (UserHasMissingRoles + CanReadUserLockedStatus)
|
||||
}
|
||||
scenario(s"We will call the $ApiEndpoint3 without user credentials", ApiEndpoint3, VersionOfApi) {
|
||||
When("We make a request v5.1.0")
|
||||
val request = (v5_1_0_Request / "users" /"PROVIDER" / "USERNAME" / "lock-status").PUT <@(user1)
|
||||
val response = makePutRequest(request, "")
|
||||
Then("error should be " + UserHasMissingRoles + CanUnlockUser)
|
||||
response.code should equal(403)
|
||||
response.body.extract[ErrorMessage].message should be (UserHasMissingRoles + CanUnlockUser)
|
||||
}
|
||||
}
|
||||
|
||||
feature(s"test $ApiEndpoint1,$ApiEndpoint2, $ApiEndpoint3, version $VersionOfApi - Wrong username") {
|
||||
scenario(s"We will call the $ApiEndpoint1 without user credentials", ApiEndpoint1, VersionOfApi) {
|
||||
val username = "USERNAME"
|
||||
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanLockUser.toString)
|
||||
When("We make a request v5.1.0")
|
||||
val request = (v5_1_0_Request /"users" / localIdentityProvider / username / "locks").POST <@(user1)
|
||||
val response = makePostRequest(request, "")
|
||||
Then("We should get a 404")
|
||||
response.code should equal(404)
|
||||
response.body.extract[ErrorMessage].message contains s"$UserNotFoundByProviderAndUsername" shouldBe(true)
|
||||
}
|
||||
scenario(s"We will call the $ApiEndpoint2 without user credentials", ApiEndpoint2, VersionOfApi) {
|
||||
val username = "USERNAME"
|
||||
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanReadUserLockedStatus.toString)
|
||||
When("We make a request v5.1.0")
|
||||
val request = (v5_1_0_Request /"users" / localIdentityProvider / username / "lock-status").GET <@(user1)
|
||||
val response = makeGetRequest(request)
|
||||
Then("We should get a 404")
|
||||
response.code should equal(404)
|
||||
response.body.extract[ErrorMessage].message contains s"$UserNotFoundByProviderAndUsername" shouldBe(true)
|
||||
}
|
||||
scenario(s"We will call the $ApiEndpoint3 without user credentials", ApiEndpoint3, VersionOfApi) {
|
||||
val username = "USERNAME"
|
||||
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanUnlockUser.toString)
|
||||
When("We make a request v5.1.0")
|
||||
val request = (v5_1_0_Request /"users" / localIdentityProvider / username / "lock-status").PUT <@(user1)
|
||||
val response = makePutRequest(request, "")
|
||||
Then("We should get a 404")
|
||||
response.code should equal(404)
|
||||
response.body.extract[ErrorMessage].message contains s"$UserNotFoundByProviderAndUsername" shouldBe(true)
|
||||
}
|
||||
}
|
||||
|
||||
feature(s"test $ApiEndpoint1,$ApiEndpoint2, $ApiEndpoint3, version $VersionOfApi - Proper values") {
|
||||
|
||||
val resource2Username = resourceUser2.name
|
||||
val resource2Provider = resourceUser2.provider
|
||||
scenario(s"We will call the $ApiEndpoint1 without user credentials", ApiEndpoint1, VersionOfApi) {
|
||||
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanLockUser.toString)
|
||||
When("We make a request v5.1.0")
|
||||
val request = (v5_1_0_Request /"users" / resource2Provider / resource2Username / "locks").POST <@(user1)
|
||||
val response = makePostRequest(request, "")
|
||||
Then("We should get a 200")
|
||||
response.code should equal(200)
|
||||
|
||||
{
|
||||
Then("We try endpoint with user2")
|
||||
val request = (v5_1_0_Request / "users" / "current").GET <@ (user2)
|
||||
val response = makeGetRequest(request)
|
||||
Then("We should get a 401")
|
||||
response.body.extract[ErrorMessage].message contains s"$UsernameHasBeenLocked" shouldBe (true)
|
||||
response.code should equal (401)
|
||||
response
|
||||
}
|
||||
}
|
||||
scenario(s"we fake failed login 10 times, cause lock the user, and check login status and unlock it ", ApiEndpoint1, ApiEndpoint2, ApiEndpoint3, VersionOfApi) {
|
||||
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanReadUserLockedStatus.toString)
|
||||
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanUnlockUser.toString)
|
||||
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanLockUser.toString)
|
||||
|
||||
// Lock the user in order to test functionality
|
||||
for (i <- 1 to 10) LoginAttempt.incrementBadLoginAttempts(resource2Provider, resource2Username)
|
||||
|
||||
When("We make a request v5.1.0")
|
||||
val request = (v5_1_0_Request / "users" / "current").GET <@ (user2)
|
||||
val response = makeGetRequest(request)
|
||||
Then("We should get a 401")
|
||||
response.code should equal(401)
|
||||
response.body.extract[ErrorMessage].message contains s"$UsernameHasBeenLocked" shouldBe(true)
|
||||
|
||||
{
|
||||
Then("We make check the lock status")
|
||||
val request = (v5_1_0_Request / "users" / resource2Provider / resource2Username / "lock-status").GET <@ (user1)
|
||||
val response = makeGetRequest(request)
|
||||
Then("We should get a 200")
|
||||
response.code should equal(200)
|
||||
response.body.extract[BadLoginStatusJson].bad_attempts_since_last_success_or_reset shouldBe (10)
|
||||
}
|
||||
|
||||
{
|
||||
Then("We unlock the user")
|
||||
val request = (v5_1_0_Request / "users" / resource2Provider / resource2Username / "lock-status").PUT <@ (user1)
|
||||
val response = makePutRequest(request, "")
|
||||
Then("We should get a 200")
|
||||
response.code should equal(200)
|
||||
}
|
||||
|
||||
{
|
||||
Then("We try endpoint with user2")
|
||||
val request = (v5_1_0_Request / "users" / "current").GET <@ (user2)
|
||||
val response = makeGetRequest(request)
|
||||
Then("We should get a 200")
|
||||
response.code should equal(200)
|
||||
response.body.extract[UserJsonV300].username shouldBe(resource2Username)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
66
obp-api/src/test/scala/code/api/v5_1_0/UserTest.scala
Normal file
66
obp-api/src/test/scala/code/api/v5_1_0/UserTest.scala
Normal file
@ -0,0 +1,66 @@
|
||||
package code.api.v5_1_0
|
||||
|
||||
import code.api.util.APIUtil.OAuth._
|
||||
import code.api.util.ApiRole.CanGetAnyUser
|
||||
import code.api.util.ErrorMessages.{UserHasMissingRoles, UserNotLoggedIn, attemptedToOpenAnEmptyBox}
|
||||
import code.api.v4_0_0.OBPAPI4_0_0.Implementations4_0_0
|
||||
import code.api.v4_0_0.{UserIdJsonV400, UserJsonV400}
|
||||
import code.api.v5_1_0.OBPAPI5_1_0.Implementations5_1_0
|
||||
import code.entitlement.Entitlement
|
||||
import code.model.UserX
|
||||
import code.users.Users
|
||||
import com.github.dwickern.macros.NameOf.nameOf
|
||||
import com.openbankproject.commons.model.ErrorMessage
|
||||
import com.openbankproject.commons.util.ApiVersion
|
||||
import org.scalatest.Tag
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
class UserTest extends V510ServerSetup {
|
||||
/**
|
||||
* Test tags
|
||||
* Example: To run tests with tag "getPermissions":
|
||||
* mvn test -D tagsToInclude
|
||||
*
|
||||
* This is made possible by the scalatest maven plugin
|
||||
*/
|
||||
object VersionOfApi extends Tag(ApiVersion.v5_1_0.toString)
|
||||
object ApiEndpoint1 extends Tag(nameOf(Implementations5_1_0.getUserByProviderAndUsername))
|
||||
|
||||
feature(s"test $ApiEndpoint1 version $VersionOfApi - Unauthorized access") {
|
||||
scenario("We will call the endpoint without user credentials", ApiEndpoint1, VersionOfApi) {
|
||||
When("We make a request v5.1.0")
|
||||
val request400 = (v5_1_0_Request / "users" / "provider"/"x" / "username" / "USERNAME").GET
|
||||
val response400 = makeGetRequest(request400)
|
||||
Then("We should get a 401")
|
||||
response400.code should equal(401)
|
||||
response400.body.extract[ErrorMessage].message should equal(UserNotLoggedIn)
|
||||
}
|
||||
}
|
||||
|
||||
feature(s"test $ApiEndpoint1 version $VersionOfApi - Authorized access") {
|
||||
scenario("We will call the endpoint with user credentials but without a proper entitlement", ApiEndpoint1, VersionOfApi) {
|
||||
When("We make a request v5.1.0")
|
||||
val request400 = (v5_1_0_Request / "users" / "provider"/defaultProvider / "username" / "USERNAME").GET <@(user1)
|
||||
val response400 = makeGetRequest(request400)
|
||||
Then("error should be " + UserHasMissingRoles + CanGetAnyUser)
|
||||
response400.code should equal(403)
|
||||
response400.body.extract[ErrorMessage].message should be (UserHasMissingRoles + CanGetAnyUser)
|
||||
}
|
||||
}
|
||||
|
||||
feature(s"test $ApiEndpoint1 version $VersionOfApi - Authorized access") {
|
||||
scenario("We will call the endpoint with user credentials and a proper entitlement", ApiEndpoint1, VersionOfApi) {
|
||||
Entitlement.entitlement.vend.addEntitlement("", resourceUser1.userId, CanGetAnyUser.toString)
|
||||
val user = UserX.createResourceUser(defaultProvider, Some("user.name.1"), None, Some("user.name.1"), None, Some(UUID.randomUUID.toString), None).openOrThrowException(attemptedToOpenAnEmptyBox)
|
||||
When("We make a request v5.1.0")
|
||||
val request400 = (v5_1_0_Request / "users" / "provider"/user.provider / "username" / user.name ).GET <@(user1)
|
||||
val response400 = makeGetRequest(request400)
|
||||
Then("We get successful response")
|
||||
response400.code should equal(200)
|
||||
response400.body.extract[UserJsonV400]
|
||||
Users.users.vend.deleteResourceUser(user.id.get)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user