2009-09-07 18:42:15 +02:00
|
|
|
/**
|
|
|
|
|
* Copyright (C) 2009 Scalable Solutions.
|
|
|
|
|
*/
|
|
|
|
|
|
2009-10-22 21:38:42 +02:00
|
|
|
package se.scalablesolutions.akka.security.samples
|
2009-09-07 18:42:15 +02:00
|
|
|
|
2009-10-17 00:37:56 +02:00
|
|
|
import se.scalablesolutions.akka.actor.{SupervisorFactory, Actor}
|
|
|
|
|
import se.scalablesolutions.akka.config.ScalaConfig._
|
|
|
|
|
import se.scalablesolutions.akka.util.Logging
|
|
|
|
|
import se.scalablesolutions.akka.security.{DigestAuthenticationActor, UserInfo}
|
|
|
|
|
import se.scalablesolutions.akka.state.TransactionalState
|
|
|
|
|
|
2009-09-07 18:42:15 +02:00
|
|
|
class Boot {
|
2009-10-22 21:38:42 +02:00
|
|
|
|
2009-09-07 18:42:15 +02:00
|
|
|
object factory extends SupervisorFactory {
|
2009-10-22 21:38:42 +02:00
|
|
|
|
2009-09-07 18:42:15 +02:00
|
|
|
override def getSupervisorConfig: SupervisorConfig = {
|
|
|
|
|
SupervisorConfig(
|
|
|
|
|
RestartStrategy(OneForOne, 3, 100),
|
2009-10-22 21:38:42 +02:00
|
|
|
// Dummy implementations of all authentication actors
|
|
|
|
|
// see akka.conf to enable one of these for the AkkaSecurityFilterFactory
|
|
|
|
|
Supervise(
|
|
|
|
|
new BasicAuthenticationService,
|
|
|
|
|
LifeCycle(Permanent, 100)) ::
|
|
|
|
|
/**
|
|
|
|
|
Supervise(
|
|
|
|
|
new DigestAuthenticationService,
|
|
|
|
|
LifeCycle(Permanent, 100)) ::
|
2009-09-07 18:42:15 +02:00
|
|
|
Supervise(
|
2009-10-22 21:38:42 +02:00
|
|
|
new SpnegoAuthenticationService,
|
2009-09-07 18:42:15 +02:00
|
|
|
LifeCycle(Permanent, 100)) ::
|
2009-10-22 21:38:42 +02:00
|
|
|
**/
|
2009-09-07 18:42:15 +02:00
|
|
|
Supervise(
|
2009-10-22 21:38:42 +02:00
|
|
|
new SecureTickActor,
|
2009-09-07 18:42:15 +02:00
|
|
|
LifeCycle(Permanent, 100)):: Nil)
|
|
|
|
|
}
|
2009-10-22 21:38:42 +02:00
|
|
|
|
2009-09-07 18:42:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val supervisor = factory.newSupervisor
|
|
|
|
|
supervisor.startSupervisor
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* In akka.conf you can set the FQN of any AuthenticationActor of your wish, under the property name: akka.rest.authenticator
|
|
|
|
|
*/
|
2009-10-22 21:38:42 +02:00
|
|
|
class DigestAuthenticationService extends DigestAuthenticationActor {
|
2009-09-07 18:42:15 +02:00
|
|
|
//If you want to have a distributed nonce-map, you can use something like below,
|
|
|
|
|
//don't forget to configure your standalone Cassandra instance
|
|
|
|
|
//
|
|
|
|
|
//makeTransactionRequired
|
|
|
|
|
//override def mkNonceMap = PersistentState.newMap(CassandraStorageConfig()).asInstanceOf[scala.collection.mutable.Map[String,Long]]
|
|
|
|
|
|
|
|
|
|
//Use an in-memory nonce-map as default
|
|
|
|
|
override def mkNonceMap = new scala.collection.mutable.HashMap[String,Long]
|
2009-10-22 21:38:42 +02:00
|
|
|
|
2009-09-07 18:42:15 +02:00
|
|
|
//Change this to whatever you want
|
|
|
|
|
override def realm = "test"
|
|
|
|
|
|
|
|
|
|
//Dummy method that allows you to log on with whatever username with the password "bar"
|
|
|
|
|
override def userInfo(username : String) : Option[UserInfo] = Some(UserInfo(username,"bar","ninja" :: "chef" :: Nil))
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-22 21:38:42 +02:00
|
|
|
class BasicAuthenticationService extends BasicAuthenticationActor {
|
|
|
|
|
|
|
|
|
|
//Change this to whatever you want
|
|
|
|
|
override def realm = "test"
|
|
|
|
|
|
|
|
|
|
//Dummy method that allows you to log on with whatever username
|
|
|
|
|
def verify(odc : Option[BasicCredentials]) : Option[UserInfo] = odc match {
|
|
|
|
|
case Some(dc) => userInfo(dc.username)
|
|
|
|
|
case _ => None
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Dummy method that allows you to log on with whatever username with the password "bar"
|
|
|
|
|
def userInfo(username : String) : Option[UserInfo] = Some(UserInfo(username,"bar","ninja" :: "chef" :: Nil))
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class SpnegoAuthenticationService extends SpnegoAuthenticationActor {
|
|
|
|
|
|
|
|
|
|
def rolesFor(user: String) = "ninja" :: "chef" :: Nil
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-07 18:42:15 +02:00
|
|
|
/**
|
2009-10-22 21:38:42 +02:00
|
|
|
* a REST Actor with class level paranoia settings to deny all access
|
2009-09-07 18:42:15 +02:00
|
|
|
*
|
|
|
|
|
* The interesting part is
|
|
|
|
|
* @RolesAllowed
|
|
|
|
|
* @PermitAll
|
|
|
|
|
* @DenyAll
|
|
|
|
|
*/
|
2009-10-22 21:38:42 +02:00
|
|
|
import java.lang.Integer
|
|
|
|
|
import javax.annotation.security.{RolesAllowed, DenyAll, PermitAll}
|
|
|
|
|
import javax.ws.rs.{GET, Path, Produces}
|
|
|
|
|
@Path("/secureticker")
|
|
|
|
|
@DenyAll
|
|
|
|
|
class SecureTickActor extends Actor with Logging {
|
2009-09-07 18:42:15 +02:00
|
|
|
|
|
|
|
|
makeTransactionRequired
|
|
|
|
|
|
|
|
|
|
case object Tick
|
|
|
|
|
private val KEY = "COUNTER";
|
|
|
|
|
private var hasStartedTicking = false;
|
2009-10-22 21:38:42 +02:00
|
|
|
private val storage = TransactionalState.newMap[String, Integer]
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* allow access for any user to the resource "/secureticker/public"
|
|
|
|
|
*/
|
|
|
|
|
@GET
|
|
|
|
|
@Produces(Array("text/xml"))
|
|
|
|
|
@Path("/public")
|
|
|
|
|
@PermitAll
|
|
|
|
|
def publicTick = tick
|
2009-09-07 18:42:15 +02:00
|
|
|
|
2009-10-22 21:38:42 +02:00
|
|
|
/**
|
|
|
|
|
* restrict access to resource "/secureticker/chef" users with "chef" role
|
|
|
|
|
*/
|
2009-09-07 18:42:15 +02:00
|
|
|
@GET
|
2009-10-22 21:38:42 +02:00
|
|
|
@Path("/chef")
|
|
|
|
|
@Produces(Array("text/xml"))
|
2009-09-07 18:42:15 +02:00
|
|
|
@RolesAllowed(Array("chef"))
|
2009-10-22 21:38:42 +02:00
|
|
|
def chefTick = tick
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* access denied because of the class level annotation for any user
|
|
|
|
|
*/
|
|
|
|
|
@GET
|
|
|
|
|
@Produces(Array("text/xml"))
|
|
|
|
|
def paranoiaTick = tick
|
|
|
|
|
|
|
|
|
|
def tick = (this !! Tick) match {
|
|
|
|
|
case(Some(counter)) => (<success>Tick: {counter}</success>)
|
|
|
|
|
case _ => (<error>Error in counter</error>)
|
|
|
|
|
}
|
2009-09-07 18:42:15 +02:00
|
|
|
|
|
|
|
|
override def receive: PartialFunction[Any, Unit] = {
|
|
|
|
|
case Tick => if (hasStartedTicking) {
|
2009-10-19 10:52:18 +02:00
|
|
|
val counter = storage.get(KEY).get.intValue
|
2009-10-22 21:38:42 +02:00
|
|
|
storage.put(KEY, counter + 1)
|
|
|
|
|
reply(new Integer(counter + 1))
|
2009-09-07 18:42:15 +02:00
|
|
|
} else {
|
2009-10-22 21:38:42 +02:00
|
|
|
storage.put(KEY, 0)
|
2009-09-07 18:42:15 +02:00
|
|
|
hasStartedTicking = true
|
2009-10-22 21:38:42 +02:00
|
|
|
reply(new Integer(0))
|
2009-09-07 18:42:15 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|