-
Notifications
You must be signed in to change notification settings - Fork 95
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add new service for updating users in kecyloak
update merge strategies to fix crypto provider add new hmda-auth service which allows users to update their keycloak account simplify build.sbt
- Loading branch information
Showing
18 changed files
with
612 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,8 @@ | ||
package hmda.auth | ||
|
||
case class VerifiedToken(token: String, id: String, name: String, username: String, email: String, roles: Seq[String], lei: String) | ||
case class VerifiedToken(token: String, id: String, userId: String, name: String, username: String, email: String, roles: Seq[String], lei: String) | ||
|
||
object VerifiedToken { | ||
def apply(): VerifiedToken = | ||
VerifiedToken("empty-token", "dev", "token", "dev", "dev@dev.com", Seq.empty, "lei") | ||
VerifiedToken("empty-token", "11111111-1111-1111-1111-111111111111", "22222222-2222-2222-2222-222222222222", "token", "dev", "dev@dev.com", Seq.empty, "lei") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
akka { | ||
log-level = INFO | ||
http.server.preview.enable-http2 = on | ||
} | ||
|
||
akka.http.parsing { | ||
max-to-strict-bytes = 20m | ||
} | ||
akka.http.server.parsing { | ||
max-content-length = 20m | ||
} | ||
|
||
akka.http.server.request-timeout = 4888888 seconds | ||
|
||
hmda { | ||
auth { | ||
http { | ||
timeout = 400000 | ||
host = "0.0.0.0" | ||
host = ${?HTTP_FILE_PROXY_HOST} | ||
port = 9095 | ||
port = ${?HTTP_FILE_PROXY_PORT} | ||
timeout = 10 | ||
} | ||
} | ||
runtime.mode = "dev" | ||
runtime.mode = ${?HMDA_RUNTIME_MODE} | ||
} | ||
|
||
keycloak { | ||
realm = "hmda2" | ||
client.id = "hmda2-api" | ||
client.id = ${?KEYCLOAK_HMDA_API_CLIENT_ID} | ||
public.key = "AYUeqDHLF_GFsZYOSMXzhBT4zyQS--KiEmBFvMzJrBA" | ||
public.key = ${?KEYCLOAK_PUBLIC_KEY_ID} | ||
auth.server.url = "https://ffiec.cfpb.gov/auth/" | ||
auth.server.url = ${?KEYCLOAK_AUTH_URL} | ||
hmda.admin.role = "hmda-admin" | ||
hmda.admin.role = ${?KEYCLOAK_HMDA_ADMIN_ROLE} | ||
admin { | ||
username = "keycloak" | ||
username = ${?KEYCLOAK_ADMIN_USERNAME} | ||
password = "keycloak" | ||
password = ${?KEYCLOAK_ADMIN_PASSWORD} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package hmda.authService.api | ||
|
||
import akka.http.scaladsl.marshalling.ToResponseMarshallable | ||
import akka.http.scaladsl.model.StatusCodes | ||
import akka.http.scaladsl.model.StatusCodes.BadRequest | ||
import akka.http.scaladsl.server.Directives._ | ||
import akka.http.scaladsl.server.directives.RouteDirectives.complete | ||
import akka.http.scaladsl.server.Route | ||
import de.heikoseeberger.akkahttpcirce.FailFastCirceSupport._ | ||
import io.circe.generic.auto._ | ||
import org.slf4j.Logger | ||
|
||
import com.typesafe.config.ConfigFactory | ||
|
||
import slick.basic.DatabaseConfig | ||
import slick.jdbc.JdbcProfile | ||
|
||
import scala.collection.JavaConverters._ | ||
import scala.concurrent._ | ||
import scala.concurrent.Future | ||
import scala.util.{ Failure, Success} | ||
|
||
import hmda.auth.OAuth2Authorization | ||
import hmda.authService.model.UserUpdate | ||
import hmda.api.http.model.ErrorResponse | ||
import hmda.institution.query.InstitutionEmailComponent | ||
|
||
import org.keycloak.admin.client.KeycloakBuilder | ||
import org.keycloak.admin.client.resource._ | ||
import org.keycloak.representations.idm._ | ||
|
||
|
||
object AuthHttpApi { | ||
def create(log: Logger)(implicit ec: ExecutionContext): OAuth2Authorization => Route = new AuthHttpApi(log).authHttpRoutes _ | ||
} | ||
private class AuthHttpApi(log: Logger)(implicit ec: ExecutionContext) extends InstitutionEmailComponent{ | ||
|
||
val config = ConfigFactory.load() | ||
val dbConfig = DatabaseConfig.forConfig[JdbcProfile]("institution_db") | ||
|
||
val keycloakServerUrl = config.getString("keycloak.auth.server.url") | ||
val keycloakRealm = config.getString("keycloak.realm") | ||
val keycloakAdminUsername = config.getString("keycloak.admin.username") | ||
val keycloakAdminPassword = config.getString("keycloak.admin.password") | ||
|
||
implicit val institutionEmailsRepository: InstitutionEmailsRepository = new InstitutionEmailsRepository(dbConfig) | ||
|
||
val keycloak = KeycloakBuilder.builder() | ||
.serverUrl(keycloakServerUrl) | ||
.realm("master") | ||
.clientId("admin-cli") | ||
.grantType("password") | ||
.username(keycloakAdminUsername) | ||
.password(keycloakAdminPassword) | ||
.build() | ||
|
||
def authHttpRoutes(oAuth2Authorization: OAuth2Authorization): Route = { | ||
encodeResponse { | ||
pathPrefix("user") { | ||
(extractUri & put) { uri => | ||
oAuth2Authorization.authorizeVerifiedToken() { token => | ||
entity(as[UserUpdate]){ userUpdate => | ||
val allUsers: UsersResource = keycloak.realm(keycloakRealm).users() | ||
val userResource: UserResource = allUsers.get(token.userId) | ||
val user: UserRepresentation = userResource.toRepresentation() | ||
val fIsValidLeis = verifyLeis(getDomainFromEmail(token.email), userUpdate.leis) | ||
if (userUpdate.firstName != user.getFirstName()) user.setFirstName(userUpdate.firstName) | ||
if (userUpdate.lastName != user.getLastName()) user.setLastName(userUpdate.lastName) | ||
onComplete(fIsValidLeis) { | ||
case Success(isValidLeis) => | ||
if (isValidLeis) { | ||
user.setAttributes(Map(("lei", List(userUpdate.leis.mkString(",")).asJava)).asJava) | ||
userResource.update(user) | ||
complete(ToResponseMarshallable(userUpdate)) | ||
} | ||
else complete((BadRequest, ErrorResponse(BadRequest.intValue, "LEIs are not authorized for the users email domain", uri.path))) | ||
case Failure(e) => | ||
complete((BadRequest, ErrorResponse(StatusCodes.InternalServerError.intValue, "Failed to fetch list of authorized LEIs for users email domain", uri.path))) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
private def getDomainFromEmail(email: String): String = email.split("@")(1) | ||
|
||
private def verifyLeis(emailDomain: String, proposedLeis: List[String]): Future[Boolean] = { | ||
findByEmailAnyYear(emailDomain).map { institutions => | ||
val availableLeis = institutions.map(institution => institution.LEI) | ||
proposedLeis.forall(availableLeis.contains) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package hmda.authService.api | ||
|
||
import akka.actor.typed.Behavior | ||
import akka.actor.typed.scaladsl.Behaviors | ||
import akka.actor.typed.scaladsl.adapter._ | ||
import akka.actor.{ ActorSystem, CoordinatedShutdown } | ||
import akka.http.scaladsl.server.Directives._ | ||
import hmda.api.http.routes.BaseHttpApi | ||
import hmda.api.http.directives.HmdaTimeDirectives._ | ||
import hmda.auth.OAuth2Authorization | ||
import akka.util.Timeout | ||
|
||
import scala.concurrent.ExecutionContext | ||
import scala.concurrent.duration._ | ||
|
||
// This is just a Guardian for starting up the API | ||
// $COVERAGE-OFF$ | ||
object HmdaAuthApi { | ||
val name: String = "hmda-auth-api" | ||
|
||
def apply(): Behavior[Nothing] = Behaviors.setup[Nothing] { ctx => | ||
implicit val system: ActorSystem = ctx.system.toClassic | ||
implicit val ec: ExecutionContext = ctx.executionContext | ||
val shutdown = CoordinatedShutdown(system) | ||
val config = ctx.system.settings.config | ||
implicit val timeout: Timeout = Timeout(config.getInt("hmda.auth.http.timeout").seconds) | ||
val log = ctx.log | ||
val oAuth2Authorization = OAuth2Authorization(log, config) | ||
val authRoute = AuthHttpApi.create(log) | ||
val routes = BaseHttpApi.routes(name) ~ authRoute(oAuth2Authorization) | ||
val host: String = config.getString("hmda.auth.http.host") | ||
val port: Int = config.getInt("hmda.auth.http.port") | ||
|
||
BaseHttpApi.runServer(shutdown, name)(timed(routes), host, port) | ||
Behaviors.empty | ||
} | ||
} | ||
// This is just a Guardian for starting up the API | ||
// $COVERAGE-OFF$ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package hmda.authService | ||
|
||
import akka.actor.typed.ActorSystem | ||
import akka.actor.typed.scaladsl.adapter._ | ||
import akka.actor.{ActorSystem => ClassicActorSystem} | ||
import akka.stream.Materializer | ||
import scala.concurrent.ExecutionContext | ||
import hmda.authService.api.HmdaAuthApi | ||
import org.slf4j.LoggerFactory | ||
|
||
object HmdaAuth extends App { | ||
|
||
val log = LoggerFactory.getLogger("hmda") | ||
|
||
log.info(""" | ||
_ _ _ _ _ _ | ||
| | | |_ __ ___ __| | __ _ / \ _ _| |_| |__ | ||
| |_| | '_ ` _ \ / _` |/ _` | / _ \| | | | __| '_ \ | ||
| _ | | | | | | (_| | (_| | / ___ \ |_| | |_| | | | | ||
|_| |_|_| |_| |_|\__,_|\__,_| /_/ \_\__,_|\__|_| |_| | ||
""".stripMargin) | ||
|
||
implicit val classicSystem: ClassicActorSystem = ClassicActorSystem("hmda-auth-system") | ||
implicit val system: ActorSystem[_] = classicSystem.toTyped | ||
implicit val materializer: Materializer = Materializer(system) | ||
implicit val ec: ExecutionContext = system.executionContext | ||
|
||
ActorSystem[Nothing](HmdaAuthApi(), HmdaAuthApi.name) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package hmda.authService.model | ||
|
||
import io.circe.Decoder | ||
import io.circe.Encoder | ||
import io.circe.generic.semiauto._ | ||
|
||
case class UserUpdate(firstName: String, lastName: String, leis: List[String]) | ||
|
||
object UserUpdate { | ||
implicit val decoder: Decoder[UserUpdate] = deriveDecoder[UserUpdate] | ||
implicit val encoder: Encoder[UserUpdate] = deriveEncoder[UserUpdate] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
apiVersion: v1 | ||
appVersion: "2.7.2" | ||
description: HMDA Auth Service | ||
name: hmda-auth | ||
version: 2.7.2 |
Empty file.
Oops, something went wrong.