Ok, it seems that oauth is not about this at all. I have implemented form-based authentication for Unfiltered myself.
The project with Form-based authentication and demo web application is here:
https://github.com/1i7/snippets/tree/master/scala-web/ScalaUnfilteredFormAuthDemoIt needs this unfiltered-jetty issue to be filed to work (enable sessions in Jetty):
https://github.com/unfiltered/unfiltered/issues/289And it also need this unfiltered-scalate issue to be fixed to be able to display info about logged in user on the ssp page:
https://github.com/unfiltered/unfiltered/issues/288Fixed source code for both modules is included to the demo project, so it will work anyway.
So, form-based authentication is implemented in unfiltered.formauth.FormAuth.scala file which contains JSecurityCheck class which extends unfiltered.filter.Plan and seems to be reusable:
https://github.com/1i7/snippets/blob/master/scala-web/ScalaUnfilteredFormAuthDemo/src/main/scala/unfiltered/formauth/FormAuth.scalaDemo application:
https://github.com/1i7/snippets/blob/master/scala-web/ScalaUnfilteredFormAuthDemo/src/main/scala/edu/nntu/scalaunfiltereddemo/UnfilteredFormAuthDemo.scalaCreate JSecurityCheck plan in this way:
val securityCheck = JSecurityCheck(
new Users() {
def authenticate(username : String, password: String) = {
username match {
case "admin" if(password == "adminpw") => Some(User("admin", "admin", "adminpw"))
case "user1" if(password == "user1pw") => Some(User("user1", "user", "user1pw"))
case "user2" if(password == "user2pw") => Some(User("user2", "user", "user2pw"))
case _ => None
}
}},
(req : HttpRequest[javax.servlet.http.HttpServletRequest]) => {
req match {
case Path(Seg("admin" :: Nil)) => Some(Set("admin"))
case Path(Seg("admin" :: "manage" :: Nil)) => Some(Set("admin"))
case Path(Seg("profile" :: Nil)) => Some(Set("admin", "user"))
case Path(Seg("profile" :: "photo" :: Nil)) => Some(Set("admin", "user"))
case _ => None
}
},
(req : HttpRequest[javax.servlet.http.HttpServletRequest], event : String) => {
import unfiltered.scalate.Scalate
event match {
case "login" =>
Unauthorized ~> Scalate(req, "auth/login.ssp")
case "error" =>
Unauthorized ~> Scalate(req, "auth/error.ssp")
case "forbidden" =>
Forbidden ~> Scalate(req, "auth/forbidden.ssp")
}
}
)
Then create application plan as always in this way:
val handlePath = unfiltered.filter.Planify {
// protected pages
case req@Path(Seg("admin" :: Nil)) =>
Ok ~> Scalate(req, "admin.ssp")
case req@Path(Seg("admin" :: "manage" :: Nil)) =>
Ok ~> Scalate(req, "admin_manage.ssp")
case req@Path(Seg("profile" :: Nil)) =>
Ok ~> Scalate(req, "profile.ssp")
case req@Path(Seg("profile" :: "photos" :: Nil)) =>
Ok ~> Scalate(req, "profile_photos.ssp")
// unprotected pages
case req@Path(Seg(Nil)) =>
Ok ~> Scalate(req, "index.ssp")
case req@Path(Seg("another" :: Nil)) =>
Ok ~> Scalate(req, "another.ssp")
}
Then start web application:
unfiltered.jetty.Server.http(8080).plan(securityCheck).plan(handlePath).run()
And this is all, when try to access protected resource under /admin or /user, authentication request page will show up automatically.