Hi Guys.
Is there a way I can apply BasicAuth to all my matchers (resources) ? Thanks. |
Administrator
|
Yep, two ways:
http://sourced.implicit.ly/net.databinder/dispatch-http/0.7.7/dispatch/Http.scala.html#19526 "as" and "as_!", difference explained in the method comments. Nathan On 11/19/10 1:23 PM, devnewb [via Databinder] wrote: Hi Guys. |
Administrator
|
Sorry I misread, thought this was on the dispatch list.
|
Administrator
|
In reply to this post by devnewb
So, I'll try this again with my brain being a little less loopy from a cold. You may have found the BasicAuth extractor:
https://github.com/n8han/Unfiltered/blob/master/library/src/main/scala/request/auths.scala#L4 If you want to apply this or any other extractor to every request, one option is to compose pattern matching expressions. This is pretty common on a small scale in unfiltered but it could also be done effectively in a bigger way. Here's some code I won't try to compile but that should be basically right: class App extends unfiltered.filter.Plan { def intent = { case BasicAuth((name, pass), req) => if (verify(name, pass)) AuthorizedApp.intent(req) else NotAuthorized case _ => NotAuthorized } object AuthorizedApp { def intent: unfiltered.filter.Plan.Intent = { case GET(...) => } } Or you could compose in many other ways. It might be interesting to have an object that extends unfiltered.filter.Plan.Intent directly and does the processing in apply(), but I can't say offhand if that would even work. The other way to handle this is as the servlet filter api would traditionally have you do it. Create one filter just for authorization, return Pass on successful authorization and NotAuthorized on any failure. Add another filter to the chain after that which would be similar to AuthorizedApp above, except that it would be an actual Filter by extending unfiltered.filter.Plan. Nathan |
I've generally followed the second approach in a few apps I've worked on. I usually have a class that I use just for Auth and take advantage of the filter chain so I can reuse the same code in other apps. I just put this auth plan before other plans in the filter chain. I think this is generally a good practice because it helps keep concerns separated and allows you to more easily swap out implementations of how you choose to handle authentication in one place.
Below is a somewhat simple shorthand for how to do that /** handles authentication. no app logic */ class Auth(authSvc: AuthSvc) extends unfiltered.filter.Plan { def intent = { case BasicAuth((name, pass), _) => if (authSvc.auth(name, pass)) Pass else NotAuthorized case _ => NotAuthorized } } /** handles app logic. no auth logic */ class App(otherSvcs: ...) extends unfiltered.filter.Plan{ def intent = { case GET(...) => } } /** serves app */ object Server { def main(args: Array[String]) { // bootstrap app deps... val authSvc = // ... unfiltered.jetty.Http(8080).filter(new Auth(authSvc)).filter(new App(...)).run } } In separating the concerns you can be a little more flexible in how you piece together your app modules. |
Also keep in mind most of unfiltered response handlers can be combined with ~>.
I probably should have also mentioned n cases where you are handling basic auth you wanted to combine Unauthorized with the WWW-Authenticate header. You can do this with unfiltered by returning something like Unauthorized ~> WWWAuthenticate("Basic realm=\"/\"") So thing I might suggest augmenting my example above with something like class Auth(authSvc: AuthSvc) extends unfiltered.filter.Plan { val AuthFail = Unauthorized ~> WWWAuthenticate("Basic realm=\"/\"") def intent = { case BasicAuth((name, pass), _) => if (authSvc.auth(name, pass)) Pass else AuthFail case _ => AuthFail } } I've considered combining them before with a higher level response function because the spec suggests they should always go together [1]. For now you can just use the ~> combinator operator. Check out the available headers [2] and status codes [3] for more info [1]: http://tools.ietf.org/html/rfc2616#section-10.4.2 [2]: http://sourced.implicit.ly/net.databinder/unfiltered/0.2.2/response/headers.scala.html [3]: http://sourced.implicit.ly/net.databinder/unfiltered/0.2.2/response/statuses.scala.html |
Thanks for your help guys. Love the framework. Will try this out when back from holiday.
|
Thanks for the support devnewb.
|
In reply to this post by soft_props
Hi.
I tried to replicate your suggestion via filters in web.xml but am struggling. I have not tried it in code like your example, do you use: unfiltered.jetty.Http(8080).filter... in production ? Thanks. |
I use unfiltered for a few internal tools at work using the unfiltered Http server abstraction but I am using what unfiltered.jetty does internally in java projects that are in production. Internally unfiltered.jetty.Http is just setting up a connector to listen on a port and a builds up a set of servlet context handlers.
I'll try to write up an example app and post to github with an example of how you can use basic auth tonight and post back here |
I just made a quick g8 template for basic auth handling that basically extends the vanilla unfiltered template
if you have giterate [1] installed. g8 softprops/unfiltered-basic-auth otherwise you can just check out the source on github here is a minimal spec https://github.com/softprops/unfiltered-basic-auth.g8/blob/master/src/main/g8/src/test/scala/ExampleSpec.scala#L19-35 and here is where I handle the filtering https://github.com/softprops/unfiltered-basic-auth.g8/blob/master/src/main/g8/src/main/scala/Example.scala#L53-85 [1]: https://github.com/n8han/giter8#readme let me know if that helps |
Awesome, thanks for your help, I will check this out tommorow! Suffering from a cold atm.
Thanks! |
Free forum by Nabble | Edit this page |