http4s-spnego

Codacy Badge Maven Central Build Status

This library provides SPNEGO Authentication as a middleware for http4s.

Project is an adaptation of akka-http-spnego, but for http4s.

How to use

  1. Add library into your dependencies:
libraryDependencies += "io.github.novakov-alexey" % "http4s-spnego_2.13" % "<version>"
or 
libraryDependencies += "io.github.novakov-alexey" % "http4s-spnego_2.12" % "<version>"
  1. Instantiate Spnego using SpnegoConfig case class:
val realm = "EXAMPLE.ORG"
val principal = s"HTTP/myservice@$realm"
val keytab = "/etc/krb5.keytab"
val debug = true
val domain = Some("myservice")
val path: Option[String] = None
val tokenValidity: FiniteDuration = 3600.seconds
val cookieName = "http4s.spnego"

val cfg = SpnegoConfig(principal, realm, keytab, debug, None, "secret", domain, path, tokenValidity, cookieName)
val spnego = Spnego[IO](cfg)
  1. Wrap AuthedRoutes with spnego#middleware, so that you can get an instance of SPNEGO token. Wrapped routes will be called successfully only if SPNEGO authentication succeeded.
import cats.effect.Sync
import cats.implicits._
import org.http4s.{AuthedRoutes, HttpRoutes}
import org.http4s.dsl.Http4sDsl

class LoginEndpoint[F[_]: Sync](spnego: Spnego[F]) extends Http4sDsl[F] {

  val routes: HttpRoutes[F] =
    spnego(AuthedRoutes.of[Token, F] {
      case GET -> Root as token =>
        Ok(s"This page is protected using HTTP SPNEGO authentication; logged in as $token")
          .map(_.addCookie(spnego.signCookie(token)))
    })
}
  1. Use routes in your server:
val login = new LoginEndpoint[IO](spnego)
val finalHttpApp = Logger.httpApp(logHeaders = true, logBody = true)(login)

BlazeServerBuilder[F]
  .bindHttp(8080, "0.0.0.0")
  .withHttpApp(finalHttpApp)
  .serve

See tests and test-server module for more examples.

Testing with test server

  1. Make sure Kerberos is installed and configured for your server and client machines.
  2. Configure test server with proper realm, principal, keytab path (see config above)
  3. Authenticate client via kinit CLI tool to the same realm used for the server side
  4. Start test server: sbt 'project test-server' run
  5. Use curl or Web-Browser to initiate a negotiation request (google for that or try this link). In case you want to test with curl, there is command for that:
curl -k --negotiate -u : -b ~/cookiejar.txt -c ~/cookiejar.txt http://<yourserver>:8080/