Skip to content

Commit

Permalink
auth middleware completed
Browse files Browse the repository at this point in the history
  • Loading branch information
ratoshniuk committed May 6, 2019
1 parent efd93d0 commit d552790
Showing 1 changed file with 51 additions and 32 deletions.
83 changes: 51 additions & 32 deletions server/src/main/scala/com/septimalmind/server.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,20 @@ import cats.effect._
import com.github.pshirshov.izumi.idealingua.runtime.rpc.http4s._
import com.github.pshirshov.izumi.idealingua.runtime.rpc.{ContextExtender, IRTClientMultiplexor, IRTServerMultiplexor, _}
import com.septimalmind.server.idl.{NetworkContext, RequestContext}
import com.septimalmind.server.idl.RequestContext.AdminRequest
import com.septimalmind.server.idl.RequestContext.{AdminRequest, ClientRequest, GuestContext}
import com.septimalmind.server.services.auth.LoginService
import com.septimalmind.server.services.users.ProfileService
import com.septimalmind.services.auth.LoginServiceWrappedServer
import com.septimalmind.services.companies.CompanyId
import com.septimalmind.services.users.{UserId, UserProfileServiceWrappedServer}
import com.septimalmind.shared.RuntimeContext
import org.http4s.{AuthScheme, Credentials, Request}
import org.http4s.headers.Authorization
import scalaz.zio.interop.Task

import scala.concurrent.duration.FiniteDuration
//import org.http4s.dsl.io
import cats.data.Kleisli
import com.github.pshirshov.izumi.functional.bio.BIO._
import com.github.pshirshov.izumi.functional.bio.BIORunner
import com.github.pshirshov.izumi.logstage.api.IzLogger
import org.http4s.Request
import org.http4s.server.{AuthMiddleware, Router}
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.syntax.kleisli._
import scalaz.zio.IO
import scalaz.zio.interop.catz._
import scala.concurrent.duration.FiniteDuration
//import org.http4s.dsl.io
import cats.data.Kleisli
import com.github.pshirshov.izumi.functional.bio.BIO._
import com.github.pshirshov.izumi.functional.bio.BIORunner
import com.github.pshirshov.izumi.logstage.api.IzLogger
import org.http4s.Request
import org.http4s.server.{AuthMiddleware, Router}
import org.http4s.server.blaze.BlazeServerBuilder
import org.http4s.syntax.kleisli._
Expand All @@ -47,10 +33,9 @@ object server extends App with RuntimeContext {

val loginAPI = new LoginServiceWrappedServer[IO, RequestContext](new LoginService[IO])


val adminAPI = new UserProfileServiceWrappedServer[IO, AdminRequest](new ProfileService[IO]).contramap[RequestContext] {
case i: AdminRequest => i
case other => throw new IllegalArgumentException("REJECTED. unknown request context")
case _ => throw new IllegalArgumentException("REJECTED. unknown request context")
}

val idlRouter = setupIDLRuntime(Set(loginAPI, adminAPI): Set[IRTWrappedService[IO, RequestContext]], Set.empty, logger)
Expand All @@ -72,28 +57,62 @@ object server extends App with RuntimeContext {
def setupIDLRuntime(services: Set[IRTWrappedService[IO, RequestContext]], clients: Set[IRTWrappedClient], logger: IzLogger)(implicit bio: BIORunner[IO], timer: Timer[IO[Throwable, ?]]) = {
val rt = new Http4sRuntime[IO, RequestContext, RequestContext, String, Unit, Unit](scala.concurrent.ExecutionContext.global)

val authUser: Kleisli[OptionT[IO[Throwable, ?], ?], Request[IO[Throwable, ?]], RequestContext] =
Kleisli {
request: Request[IO[Throwable, ?]] =>
val context = RequestContext.AdminRequest(UserId(UUID.randomUUID(), UUID.randomUUID()), NetworkContext(request.remoteAddr.getOrElse("0.0.0.0")))
OptionT.liftF(Task(context))
}
val clientMultiplexor: IRTClientMultiplexor[IO] = new IRTClientMultiplexor[IO](clients)

val listeners: Set[WsSessionListener[String]] = Set.empty
val serverMultiplexor = new IRTServerMultiplexor[IO, RequestContext, RequestContext](services, ContextExtender.id)

val (listeners, wsContextProvider, wsSessionStorage) = setupWsContext(rt, logger, clientMultiplexor)

val printer: io.circe.Printer = io.circe.Printer.spaces2

val codec: IRTClientMultiplexor[IO] = new IRTClientMultiplexor[IO](clients)
val server = new HttpServer[rt.type](rt.self, serverMultiplexor, clientMultiplexor, AuthMiddleware(authUser), wsContextProvider, wsSessionStorage, listeners.toSeq, logger, printer)

val wsContextProvider: WsContextProvider[IO, RequestContext, String] = new IdContextProvider[rt.type](rt.self)
server.service
}

val wsSessionStorage: WsSessionsStorage[IO, String, RequestContext] = new WsSessionsStorageImpl[rt.type](rt.self, logger, codec)
val authUser: Kleisli[OptionT[IO[Throwable, ?], ?], Request[IO[Throwable, ?]], RequestContext] =
Kleisli {
request: Request[IO[Throwable, ?]] => OptionT.liftF(prepareRequest(request))
}


private def prepareRequest(request: Request[IO[Throwable, ?]]) : Task[RequestContext] = {
lazy val networkContext = NetworkContext(request.remoteAddr.getOrElse("0.0.0.0"))
import org.http4s.syntax.string._
val privateScheme = "Api-Key".ci
request.headers.collectFirst {
case h : Authorization =>
h.credentials match {
case Credentials.Token(scheme, token) if scheme == AuthScheme.Bearer =>
parseAsClient(networkContext, token)
case Credentials.Token(scheme, token) if scheme == privateScheme =>
parseAsAdmin(networkContext, token)
}
}.getOrElse(IO.sync(GuestContext(networkContext)))
}

val multiplexor = new IRTServerMultiplexor[IO, RequestContext, RequestContext](services, ContextExtender.id)
private def parseAsAdmin(networkContext: NetworkContext, token: String) : Task[AdminRequest] = {
token.split("==").toList match {
case "admin" :: str :: Nil =>
IO.syncThrowable(UserId.parse(str)).map(AdminRequest(_, networkContext))
case _ =>
IO.fail(new Exception("wrong token"))
}
}

val server = new HttpServer[rt.type](rt.self, multiplexor, codec, AuthMiddleware(authUser), wsContextProvider, wsSessionStorage, listeners.toSeq, logger, printer) {
private def parseAsClient(networkContext: NetworkContext, token: String) : Task[ClientRequest] = {
token.split("==").toList match {
case "user" :: str :: Nil =>
IO.syncThrowable(UserId.parse(str)).map(ClientRequest(_, networkContext))
case _ =>
IO.fail(new Exception("wrong token"))
}
}

server.service
private def setupWsContext(rt: Http4sRuntime[IO, RequestContext, RequestContext, String, Unit, Unit], logger: IzLogger, codec: IRTClientMultiplexor[IO]) = {
val listeners: Set[WsSessionListener[String]] = Set.empty
val wsContextProvider: WsContextProvider[IO, RequestContext, String] = new IdContextProvider[rt.type](rt.self)
val wsSessionStorage: WsSessionsStorage[IO, String, RequestContext] = new WsSessionsStorageImpl[rt.type](rt.self, logger, codec)
(listeners, wsContextProvider, wsSessionStorage)
}
}

0 comments on commit d552790

Please sign in to comment.