Skip to content

Instantly share code, notes, and snippets.

@kenmazaika
Created November 3, 2012 17:15
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kenmazaika/4007979 to your computer and use it in GitHub Desktop.
Save kenmazaika/4007979 to your computer and use it in GitHub Desktop.
Jetty + Akka + Scala Basic Auth
package com.pandemic.recommendation_core.web
import akka.actor._
import akka.actor.Actor.actorOf
import akka.http._
import org.eclipse.jetty.server.Server
import org.eclipse.jetty.servlet.ServletHolder
import org.eclipse.jetty.servlet.ServletContextHandler
import org.eclipse.jetty.http.security.Constraint;
import org.eclipse.jetty.http.security.Credential;
import org.eclipse.jetty.security.ConstraintMapping;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.security.SecurityHandler;
import scala.collection.mutable.HashMap
import com.pandemic.recommendation_core.common._
import com.pandemic.recommendation_core.common.config.ProjectConfig
/**
* This class manually embeds Jetty (see http://wiki.eclipse.org/Jetty/Tutorial/Embedding_Jetty)
* and forwards requests from it to Akka HTTP. There are many other ways to set things up,
* for example you could use the Akka Microkernel, or use the standard Jetty distribution's
* prebuilt servlet container. Whatever you are used to. See also:
* http://akka.io/docs/akka/1.2/scala/http.html
*
* You don't have to use Akka HTTP either of course, you could just write a subclass of
* AbstractHandler and handle requests yourself. One advantage of Akka HTTP is that it
* automatically suspends the Jetty requests so they are truly async (they don't tie
* up a thread).
*/
class WebServer(config: ProjectConfig) {
// to use Akka HTTP, we need a RootEndpoint which is an actor that
// comes with Akka
private val rootEndpoint = actorOf[RootEndpoint]
// we register this bootstrap actor with the RootEndpoint, and have
// it dispatch requests for us
private val bootstrap = actorOf(new WebActor(rootEndpoint, config))
private var maybeServer: Option[Server] = None
def start(): Unit = {
if (maybeServer.isDefined)
throw new IllegalStateException("can't start http server twice")
rootEndpoint.start
bootstrap.start
val server = new Server(config.port.getOrElse(8080))
// here we pull in the servlet container; if we didn't want to use AkkaMistServlet,
// we could just subclass AbstractHandler and skip this dependency.
val handler = new ServletContextHandler(ServletContextHandler.SESSIONS)
val users = new HashMap[String, String]
users += "user1" -> "omg"
users += "user2" -> "lol"
handler.setSecurityHandler(basicAuth(users, "Private!"));
handler.setContextPath("/")
// AkkaMistServlet forwards requests to the rootEndpoint which
// in turn forwards them to our bootstrap actor.
handler.addServlet(new ServletHolder(new AkkaMistServlet()), "/*")
server.setHandler(handler)
server.start()
maybeServer = Some(server)
}
def run(): Unit = {
maybeServer foreach { _.join() }
}
def stop() = {
maybeServer foreach { server =>
server.stop()
}
maybeServer = None
bootstrap.stop
rootEndpoint.stop
}
//TODO remove basic auth
// lifted from: https://github.com/jesperfj/jetty-secured-sample/blob/master/src/main/java/HelloWorld.java
// then converted to scala and modified
def basicAuth(users: HashMap[String, String], realm: String): SecurityHandler = {
var l = new HashLoginService();
users.foreach {
case(username, password) =>
l.putUser(username, Credential.getCredential(password), List("user").toArray)
}
l.setName(realm)
var constraint = new Constraint()
constraint.setName(Constraint.__BASIC_AUTH);
constraint.setRoles(List("user").toArray);
constraint.setAuthenticate(true);
var cm = new ConstraintMapping()
cm.setConstraint(constraint)
// add basic auth to the following endpoints
cm.setPathSpec("/api/v1/omgs")
var csh = new ConstraintSecurityHandler()
csh.setAuthenticator(new BasicAuthenticator())
csh.setRealmName("myrealm")
csh.addConstraintMapping(cm)
csh.setLoginService(l)
return csh
}
}
@igreenfield
Copy link

Hi could you share "AkkaMistServlet" code?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment