Unfiltered in-page authentication

28 views
Skip to first unread message

Anton Moiseev

unread,
Jan 16, 2015, 7:30:03 PM1/16/15
to unfilter...@googlegroups.com
Hello,

I have been experimenting with Unfiltered BasicAuth, like here:
http://unfiltered.databinder.net/Who’s+Who.html , here
http://www.gerd-riesselmann.net/development/authentication-using-unfiltered-scala/ , and here
http://databinder.3617998.n2.nabble.com/apply-BasicAuth-to-all-matchers-td5755629.html , and here's my own demo:
https://github.com/1i7/snippets/blob/master/scala-web/ScalaUnfilteredBasicAuthDemo/src/main/scala/edu/nntu/scalaunfiltereddemo/UnfilteredBasicAuthDemo.scala

and seems I have no problems with that. But I want in-page authentication without browser login/password window, I want to provide login/password text fields inside html page myself, as all sites do (except router config pages). With tomcat I have been using some kind of special Realm for that. Asking for examples of something similar with Unfiltered. I'v been looking at unfiltered-auth and unfiltered-auth2 modules, but according to general descripition for me they currently seem be like tools for 3pty authentication (like facebook login to any site). Should I use auth/auth2 for simple (in-page) authentication of there is something different way for that?

Anton Moiseev

unread,
Jan 16, 2015, 8:59:39 PM1/16/15
to unfilter...@googlegroups.com
For tomcat webapp I mean authentication similar to the one based on the following part from web.xml: 

  <security-constraint>
        <web-resource-collection>
            <web-resource-name>Applicatin administrator resources</web-resource-name>
            <url-pattern>/admin/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>ADMIN</role-name>
        </auth-constraint>
    </security-constraint>
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Common user resources</web-resource-name>
            <url-pattern>/user/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>USER</role-name>
        </auth-constraint>
    </security-constraint>
    <login-config>
        <auth-method>FORM</auth-method>
        <realm-name>FORM-based authentication area</realm-name>
        <form-login-config>
            <form-login-page>/WEB-INF/login.jsp</form-login-page>
            <form-error-page>/WEB-INF/error.jsp</form-error-page>
        </form-login-config>
    </login-config>

Anton Moiseev

unread,
Jan 28, 2015, 8:49:12 AM1/28/15
to unfilter...@googlegroups.com
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/ScalaUnfilteredFormAuthDemo

It needs this unfiltered-jetty issue to be filed to work (enable sessions in Jetty): https://github.com/unfiltered/unfiltered/issues/289
And 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/288

Fixed 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.scala

Demo application: https://github.com/1i7/snippets/blob/master/scala-web/ScalaUnfilteredFormAuthDemo/src/main/scala/edu/nntu/scalaunfiltereddemo/UnfilteredFormAuthDemo.scala

Create 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.

Anton Moiseev

unread,
Jan 28, 2015, 1:15:59 PM1/28/15
to unfilter...@googlegroups.com
A better way to handle restricted areas:


  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" :: _)) => Some(Set("admin"))
        case Path(Seg("profile" :: _)) => Some(Set("admin", "user"))
Reply all
Reply to author
Forward
0 new messages