diff --git a/akka-samples-security/src/main/resources/akka.conf b/akka-samples-security/src/main/resources/akka.conf
new file mode 100644
index 0000000000..e2a93561f0
--- /dev/null
+++ b/akka-samples-security/src/main/resources/akka.conf
@@ -0,0 +1,35 @@
+####################
+# Akka Config File #
+####################
+
+# This file has all the default settings, so all these could be remove with no visible effect.
+# Modify as needed.
+
+
+ version = "0.6"
+
+ boot = ["se.scalablesolutions.akka.security.samples.Boot"] # FQN to the class doing initial active object/actor
+ # supervisor bootstrap, should be defined in default constructor
+
+
+ filters = "se.scalablesolutions.akka.security.AkkaSecurityFilterFactory"
+
+ # only one authenticator can be enabled for the security filter factory
+ authenticator = "se.scalablesolutions.akka.security.samples.BasicAuthenticationService"
+# authenticator = "se.scalablesolutions.akka.security.samples.DigestAuthenticationService"
+# authenticator = "se.scalablesolutions.akka.security.samples.SpnegoAuthenticationService"
+
+#
+#
+# servicePrincipal = "HTTP/localhost@EXAMPLE.COM"
+# keyTabLocation = "URL to keytab"
+# kerberosDebug = "true"
+# realm = "EXAMPLE.COM"
+#
+
+ # service = on
+ # hostname = "localhost"
+ # port = 9998
+
+
+
diff --git a/akka-samples-security/src/main/scala/SimpleService.scala b/akka-samples-security/src/main/scala/SimpleService.scala
index 2f38c23ef9..db328cc6ad 100644
--- a/akka-samples-security/src/main/scala/SimpleService.scala
+++ b/akka-samples-security/src/main/scala/SimpleService.scala
@@ -2,7 +2,7 @@
* Copyright (C) 2009 Scalable Solutions.
*/
-package sample.secure
+package se.scalablesolutions.akka.security.samples
import se.scalablesolutions.akka.actor.{SupervisorFactory, Actor}
import se.scalablesolutions.akka.config.ScalaConfig._
@@ -10,21 +10,31 @@ import se.scalablesolutions.akka.util.Logging
import se.scalablesolutions.akka.security.{DigestAuthenticationActor, UserInfo}
import se.scalablesolutions.akka.state.TransactionalState
-import javax.annotation.security.RolesAllowed
-import javax.ws.rs.{GET, Path, Produces}
-
class Boot {
+
object factory extends SupervisorFactory {
+
override def getSupervisorConfig: SupervisorConfig = {
SupervisorConfig(
RestartStrategy(OneForOne, 3, 100),
+ // Dummy implementations of all authentication actors
+ // see akka.conf to enable one of these for the AkkaSecurityFilterFactory
Supervise(
- new SimpleAuthenticationService,
+ new BasicAuthenticationService,
+ LifeCycle(Permanent, 100)) ::
+ /**
+ Supervise(
+ new DigestAuthenticationService,
LifeCycle(Permanent, 100)) ::
Supervise(
- new SecureService,
+ new SpnegoAuthenticationService,
+ LifeCycle(Permanent, 100)) ::
+ **/
+ Supervise(
+ new SecureTickActor,
LifeCycle(Permanent, 100)):: Nil)
}
+
}
val supervisor = factory.newSupervisor
@@ -34,7 +44,7 @@ class Boot {
/*
* In akka.conf you can set the FQN of any AuthenticationActor of your wish, under the property name: akka.rest.authenticator
*/
-class SimpleAuthenticationService extends DigestAuthenticationActor {
+class DigestAuthenticationService extends DigestAuthenticationActor {
//If you want to have a distributed nonce-map, you can use something like below,
//don't forget to configure your standalone Cassandra instance
//
@@ -43,6 +53,7 @@ class SimpleAuthenticationService extends DigestAuthenticationActor {
//Use an in-memory nonce-map as default
override def mkNonceMap = new scala.collection.mutable.HashMap[String,Long]
+
//Change this to whatever you want
override def realm = "test"
@@ -50,38 +61,89 @@ class SimpleAuthenticationService extends DigestAuthenticationActor {
override def userInfo(username : String) : Option[UserInfo] = Some(UserInfo(username,"bar","ninja" :: "chef" :: Nil))
}
+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
+
+}
+
/**
- * This is merely a secured version of the scala-sample
+ * a REST Actor with class level paranoia settings to deny all access
*
* The interesting part is
* @RolesAllowed
* @PermitAll
* @DenyAll
*/
+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 {
-@Path("/securecount")
-class SecureService extends Actor with Logging {
makeTransactionRequired
case object Tick
private val KEY = "COUNTER";
private var hasStartedTicking = false;
- private val storage = TransactionalState.newMap[String, Integer]
+ private val storage = TransactionalState.newMap[String, Integer]
+ /**
+ * allow access for any user to the resource "/secureticker/public"
+ */
@GET
- @Produces(Array("text/html"))
+ @Produces(Array("text/xml"))
+ @Path("/public")
+ @PermitAll
+ def publicTick = tick
+
+ /**
+ * restrict access to resource "/secureticker/chef" users with "chef" role
+ */
+ @GET
+ @Path("/chef")
+ @Produces(Array("text/xml"))
@RolesAllowed(Array("chef"))
- def count = (this !! Tick).getOrElse(Error in counter)
+ 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)) => (Tick: {counter})
+ case _ => (Error in counter)
+ }
override def receive: PartialFunction[Any, Unit] = {
case Tick => if (hasStartedTicking) {
val counter = storage.get(KEY).get.intValue
- storage.put(KEY, new Integer(counter + 1))
- reply(Tick:{counter + 1})
+ storage.put(KEY, counter + 1)
+ reply(new Integer(counter + 1))
} else {
- storage.put(KEY, new Integer(0))
+ storage.put(KEY, 0)
hasStartedTicking = true
- reply(Tick: 0)
+ reply(new Integer(0))
}
}
}
\ No newline at end of file
diff --git a/akka-samples-security/src/main/webapp/WEB-INF/web.xml b/akka-samples-security/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000000..a04d912c1d
--- /dev/null
+++ b/akka-samples-security/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,21 @@
+
+
+
+ akka-security-samples
+
+
+ AkkaServlet
+ se.scalablesolutions.akka.rest.AkkaServlet
+
+
+
+ AkkaServlet
+ /*
+
+
+
+
+