Permalink
Browse files

Major overhaul of the REST chapter, lots of little changes elsewhere

  • Loading branch information...
1 parent 6c81fcb commit 76b71e0f1fbe7a05366975dcb83f751ca4a8cb43 @dchenbecker dchenbecker committed Oct 11, 2010
Showing with 3,389 additions and 973 deletions.
  1. +644 −311 chap-advanced.lyx
  2. +14 −3 chap-demoapp.lyx
  3. +11 −1 chap-js_commands.lyx
  4. +2 −2 chap-sitemap.lyx
  5. +168 −75 chap-template_xhtml.lyx
  6. +2,515 −581 chap-web_services.lyx
  7. +35 −0 chap-welcome.lyx
View
955 chap-advanced.lyx
@@ -3615,6 +3615,26 @@ name "sub:HTTP-Authentication"
\end_inset
+\begin_inset Index
+status open
+
+\begin_layout Plain Layout
+HTTP ! authentication
+\end_layout
+
+\end_inset
+
+
+\begin_inset Index
+status open
+
+\begin_layout Plain Layout
+Authentication
+\end_layout
+
+\end_inset
+
+
\end_layout
\begin_layout Standard
@@ -3623,9 +3643,13 @@ HTTP authentication is described by RFC 2617
status open
\begin_layout Plain Layout
-\begin_inset CommandInset href
-LatexCommand href
-target "http://www.isi.edu/in-notes/rfc2617.txt"
+\begin_inset Flex URL
+status open
+
+\begin_layout Plain Layout
+
+http://www.isi.edu/in-notes/rfc2617.txt
+\end_layout
\end_inset
@@ -3637,37 +3661,125 @@ target "http://www.isi.edu/in-notes/rfc2617.txt"
.
It describes the means of protecting server resources and allowing access
only to authorized entities.
- As you may know any J(2)EE web container provides HTTP authentication support
- mostly using JAAS
+ As you may know, any J(2)EE web container provides HTTP authentication
+ support using JAAS
\begin_inset Foot
-status open
+status collapsed
\begin_layout Plain Layout
Java Authentication and Authorization Service.
- More informations can be found at
-\begin_inset CommandInset href
-LatexCommand href
-target "http://java.sun.com/javase/6/docs/technotes/guides/security/jaas/JAASRefGuide.html"
+ More information can be found at
+\begin_inset Flex URL
+status open
+
+\begin_layout Plain Layout
+
+http://java.sun.com/javase/6/docs/technotes/guides/security/jaas/JAASRefGuide.html
+\end_layout
+
+\end_inset
+
+
+\end_layout
\end_inset
+\begin_inset Index
+status open
+
+\begin_layout Plain Layout
+Authentication ! JAAS
\end_layout
\end_inset
- .
- But this appoach is not without caveats.
- For instance if you provide your own LoginModule or CallbackHandler implementat
-ion this will not be loaded by the web application classloader but instead
- by the container classloader (..
- at least in tomcat).
- This means that if your code has other dependencies that you can not use
- these dependencies from your web application since web application classloader
- sits below container's classloader in the delegation chain.
- Besides all these using Scala's power the developer experience of protecting
- server resources using HTTP authentication can be simplified a lot.
- Lift supports both basic and digest authentications, Basic is shown below:
+.
+ However, this approach has limitations.
+ For example, if you provide your own
+\family typewriter
+LoginModule
+\family default
+ or
+\family typewriter
+CallbackHandler
+\family default
+ implementation this will not be loaded by the web application classloader
+ but instead by the container classloader (at least in tomcat).
+ This can lead to dependency loading issues since the web application classloade
+r sits below the container's classloader in the delegation chain.
+ Lift, however, provides supports for both basic and digest authentications
+ via a simplified, scala-oriented API that you can use directly.
+ This API provides not only direct support for the HTTP authentication mechanism
+s, but also a path and role based authorization mechanism.
+ The following sections show how we use basic authentication to protect
+ our REST API (Chapter
+\begin_inset CommandInset ref
+LatexCommand vref
+reference "cha:Web-Services"
+
+\end_inset
+
+).
+\end_layout
+
+\begin_layout Subsection
+Determining which Resources to Protect
+\end_layout
+
+\begin_layout Standard
+The first thing we need to do is tell Lift which resources are protected
+ by authentication.
+ This is done by configuring
+\family typewriter
+LiftRules.httpAuthProtectedResources
+\begin_inset Index
+status open
+
+\begin_layout Plain Layout
+httpAuthProtectedResources
+\end_layout
+
+\end_inset
+
+
+\family default
+ with one or more
+\family typewriter
+PartialFunction[Req,Box[Role]]
+\family default
+
+\begin_inset Foot
+status open
+
+\begin_layout Plain Layout
+
+\family typewriter
+net.liftweb.http.auth.Role
+\end_layout
+
+\end_inset
+
+ to match on the request.
+ Listing
+\begin_inset CommandInset ref
+LatexCommand ref
+reference "lst:HTTP-auth-define-resources"
+
+\end_inset
+
+ shows the PartialFunction defined in our
+\family typewriter
+DispatchRestAPI
+\family default
+ object (Section
+\begin_inset CommandInset ref
+LatexCommand vref
+reference "sub:REST-Custom-Dispatch"
+
+\end_inset
+
+) used to protect our REST API from unauthorized access.
\end_layout
\begin_layout Standard
@@ -3680,7 +3792,14 @@ status open
\begin_inset Caption
\begin_layout Plain Layout
-HTTP Authentication example
+Defining Protected Resources
+\begin_inset CommandInset label
+LatexCommand label
+name "lst:HTTP-auth-define-resources"
+
+\end_inset
+
+
\end_layout
\end_inset
@@ -3690,225 +3809,451 @@ HTTP Authentication example
\begin_layout Plain Layout
-import auth._
+ // We explicitly protect GET and PUT requests in our REST API
\end_layout
\begin_layout Plain Layout
+ import net.liftweb.http.auth.AuthRole
\end_layout
\begin_layout Plain Layout
-class Boot {
+ def protection : LiftRules.HttpAuthProtectedResourcePF = {
\end_layout
\begin_layout Plain Layout
- def boot = {
+ case Req(List("api", "account", accountId), _, PutRequest) =>
\end_layout
\begin_layout Plain Layout
- ...
+ Full(AuthRole("editAcct:" + accountId))
\end_layout
\begin_layout Plain Layout
- LiftRules.protectedResource.append {
+ case Req(List("api", "account", accountId), _, GetRequest) =>
\end_layout
\begin_layout Plain Layout
- case (ParsePath("users" :: _, _, _, _)) => Full(AuthRole("admin"))
+ Full(AuthRole("viewAcct:" + accountId))
\end_layout
\begin_layout Plain Layout
- }
+ // If the account is public, don't enforce auth
\end_layout
\begin_layout Plain Layout
-
+ case Req(List("api", "expense", Expense(e, true)), _, GetRequest) =>
+ Empty
\end_layout
\begin_layout Plain Layout
- LiftRules.authentication = HttpBasicAuthentication("lift") {
+ case Req(List("api", "expense", Expense(e, _)), _, GetRequest) =>
\end_layout
\begin_layout Plain Layout
- case ("John", "12test34", req) =>
+ Full(AuthRole("viewAcct:" + e.account.obj.open_!.id))
\end_layout
\begin_layout Plain Layout
- println("John is authenticated!")
+ }
\end_layout
-\begin_layout Plain Layout
+\end_inset
+
- userRoles(AuthRole("admin"))
\end_layout
-\begin_layout Plain Layout
+\begin_layout Standard
+The
+\family typewriter
+PartialFunction
+\family default
+ matches on the
+\family typewriter
+Req
+\family default
+ and can either return an
+\family typewriter
+Empty
+\family default
+, indicating that the given request does not require authentication, or
+ a
+\family typewriter
+Full[Role]
+\family default
+, that indicates which R
+\family typewriter
+ole
+\family default
+ a user requires to be authorized to access the given resource.
+ One important thing to remember is that HTTP authentication and SiteMap
+ access control (Section
+\begin_inset CommandInset ref
+LatexCommand vref
+reference "sec:SiteMap-Access-Control"
- true
+\end_inset
+
+) are synergistic, so make sure that you configure both properly.
+ We will discuss
+\family typewriter
+Role
+\family default
+s further in Section
+\begin_inset CommandInset ref
+LatexCommand ref
+reference "sub:Role-Hierarchies"
+
+\end_inset
+
+, but for now you can simply consider them as
+\family typewriter
+String
+\family default
+ attributes associated with the current session.
+ Once we've defined which resources are to be protected, we need to hook
+ our
+\family typewriter
+PartialFunction
+\family default
+ into
+\family typewriter
+LiftRules
+\family default
+ in the
+\family typewriter
+Boot.boot
+\family default
+ method, shown in Listing
+\begin_inset CommandInset ref
+LatexCommand ref
+reference "lst:Hooking-Resource-Protection"
+
+\end_inset
+
+.
\end_layout
+\begin_layout Standard
+\begin_inset listings
+inline false
+status open
+
\begin_layout Plain Layout
- }
-\end_layout
+\begin_inset Caption
\begin_layout Plain Layout
+Hooking Resource Protection
+\begin_inset CommandInset label
+LatexCommand label
+name "lst:Hooking-Resource-Protection"
+
+\end_inset
+
\end_layout
-\begin_layout Plain Layout
+\end_inset
+
- ...
\end_layout
\begin_layout Plain Layout
- }
+// Hook in our REST API auth
\end_layout
\begin_layout Plain Layout
-}
+LiftRules.httpAuthProtectedResource.append(DispatchRestAPI.protection)
\end_layout
\end_inset
-Here we just told Lift that /users path is a protected resource and only
- by users that have the Role admin.
- So here we have both authentication and authorization.
- If this function returns an Empty box it means that this resource is not
- bound to any Role meaning that only authentication will be performed, not
- authorization.
- Secondly using
+
+\end_layout
+
+\begin_layout Subsection
+Providing the Authentication Hook
+\end_layout
+
+\begin_layout Standard
+After we've defined what resources we want to protect, we need to configure
+ the
\family typewriter
LiftRules.authentication
\family default
- we told Lift that we want BasicAuthentication and of course we are passing
- the function that actually does the authentication.
- This function is actually a PartialFunction[(String, String, Req), Boolean].
- First two members of the tuple are username and password, then the Req
- object.
- In the above example we're basically saying that if user is authenticating
- itself as
-\begin_inset Quotes eld
-\end_inset
+ function to perform the actual authentication.
+ Lift supports both HTTP Basic and Digest authentication schemes, which
+ we'll cover in the next two sections.
+\end_layout
-John
-\begin_inset Quotes erd
-\end_inset
+\begin_layout Subsubsection
+HTTP Basic Authentication
+\end_layout
- and password is
-\begin_inset Quotes eld
-\end_inset
+\begin_layout Standard
+HTTP Basic authentication is provided by the
+\family typewriter
+net.liftweb.http.auth.HttpBasicAuthentication
+\family default
+ implementation class, constructed using the authentication realm name as
+ well as a
+\family typewriter
+PartialFunction[(String, String, Req), Boolean]
+\family default
+ that actually does the authentication.
+ The tuple passed to the
+\family typewriter
+PartialFunction
+\family default
+ consists of the attempted username password, and the request object (
+\family typewriter
+Req
+\family default
+).
+ It's your responsibility to return
+\family typewriter
+true
+\family default
+ or
+\family typewriter
+false
+\family default
+ to indicate whether the provided credentials succeed.
+ Listing
+\begin_inset CommandInset ref
+LatexCommand ref
+reference "lst:Performing-Basic-Authentication"
-12test34
-\begin_inset Quotes erd
\end_inset
- the access to the protected resource will be granted (since our function
- returns true).
- But in our authentication function we also specify the role for user
-\begin_inset Quotes eld
-\end_inset
+ shows the code in
+\family typewriter
+Boot.boot
+\family default
+ that PocketChange uses to perform authentication based on the user's email
+ address and password.
+ Note that when authentication succeeds for a given user not only do we
+ return true, but we set the user as logged in (via
+\family typewriter
+User.logUserIn
+\family default
+) and we compile a set of all of the
+\family typewriter
+Role
+\family default
+s that the user so that Lift knows which protected resources the user may
+ access.
+ The
+\family typewriter
+ net.liftweb.http.auth.userRoles
+\family default
+
+\family typewriter
+RequestVar
+\family default
+ is a built-in construct in Lift that the authentication backend uses for
+ bookkeeping.
+\end_layout
-John
-\begin_inset Quotes erd
-\end_inset
+\begin_layout Standard
+\begin_inset listings
+inline false
+status open
+
+\begin_layout Plain Layout
+
+\begin_inset Caption
+
+\begin_layout Plain Layout
+Performing Basic Authentication
+\begin_inset CommandInset label
+LatexCommand label
+name "lst:Performing-Basic-Authentication"
- as being
-\begin_inset Quotes eld
\end_inset
-admin
-\begin_inset Quotes erd
+
+\end_layout
+
\end_inset
-.
-
-\family typewriter
-userRole
-\family default
- is a RequestVar that will be used later on by Lift.
+
\end_layout
-\begin_layout Standard
-So at runtime when user tries to access /users Lift knows that this is a
- protected resource and only an admin can access it.
- Therefore Lift is sending down to client a 401 HTTP status (unauthorized
- response).
- User will enter the credentials and if they match with username John and
- password 12test34 we got a successful authentication and because the role
- we set is admin which matches with the role assigned to the protected resource,
- the /users resource is served to client.
-
+\begin_layout Plain Layout
+
+import net.liftweb.http.auth.{AuthRole,HttpBasicAuthentication,userRoles}
\end_layout
-\begin_layout Standard
-A Role is an n-ary tree structure.
- So when we assign a Role to a protectedResource we can actually provide
- an entire tree such as:
+\begin_layout Plain Layout
+
+LiftRules.authentication = HttpBasicAuthentication("PocketChange") {
\end_layout
-\begin_layout Standard
-\begin_inset Float figure
-wide false
-sideways false
-status open
+\begin_layout Plain Layout
+
+ case (userEmail, userPass, _) => {
+\end_layout
+
+\begin_layout Plain Layout
+
+ logger.debug("Authenticating: " + userEmail)
+\end_layout
+
+\begin_layout Plain Layout
+
+ User.find(By(User.email, userEmail)).map { user =>
+\end_layout
+
+\begin_layout Plain Layout
+
+ if (user.password.match_?(userPass)) {
+\end_layout
+
+\begin_layout Plain Layout
+
+ logger.debug("Auth succeeded for " + userEmail)
+\end_layout
+
+\begin_layout Plain Layout
+
+ User.logUserIn(user)
+\end_layout
+
+\begin_layout Plain Layout
+
+\end_layout
+
+\begin_layout Plain Layout
+
+ // Compute all of the user roles
+\end_layout
+
+\begin_layout Plain Layout
+
+ userRoles(user.editable.map(acct => AuthRole("editAcct:" + acct.id))
+ ++
+\end_layout
+
+\begin_layout Plain Layout
+
+ user.allAccounts.map(acct => AuthRole("viewAcct:" + acct.id)))
+\end_layout
+
+\begin_layout Plain Layout
+
+ true
+\end_layout
+
+\begin_layout Plain Layout
+
+ } else {
+\end_layout
+
+\begin_layout Plain Layout
+
+ logger.warn("Auth failed for " + userEmail)
+\end_layout
+
+\begin_layout Plain Layout
+
+ false
+\end_layout
+
+\begin_layout Plain Layout
+
+ }
+\end_layout
\begin_layout Plain Layout
-\align center
-\begin_inset Graphics
- filename images/roles.png
- lyxscale 10
- width 5in
-\end_inset
+ } openOr false
+\end_layout
+\begin_layout Plain Layout
+ }
\end_layout
\begin_layout Plain Layout
-\begin_inset Caption
-\begin_layout Plain Layout
-Roles hierarchy example
+}
\end_layout
\end_inset
\end_layout
+\begin_layout Subsubsection
+HTTP Digest Authentication
+\end_layout
+
+\begin_layout Standard
+HTTP Digest authentication is provided by the
+\family typewriter
+net.liftweb.http.auth.HttpDigestAuthentication
+\family default
+ implementation class.
+ Like Basic authentication, the
+\family typewriter
+HttpDigestAuthentication
+\family default
+ instance is constructed with a realm name and a
+\family typewriter
+PartialFunction
+\family default
+, but in this case the
+\family typewriter
+PartialFunction
+\family default
+ uses a tuple of
+\family typewriter
+(String,Req,(String)
+\begin_inset Formula $\Rightarrow$
\end_inset
+Boolean)
+\family default
+.
+ The first parameter is still the username, and the second parameter is
+ the request instance, but the third parameter is a function that will compute
+ and compare the digest for authentication based on a
+\emph on
+plaintext
+\emph default
+ password.
+ This means that if we want to use Digest authentication, we need to be
+ able to retrieve a plaintext password for the user from the database somehow.
+ Listing
+\begin_inset CommandInset ref
+LatexCommand ref
+reference "lst:HTTP-Digest-Authentication"
-\end_layout
+\end_inset
-\begin_layout Standard
-Assume that your application uses a roles structure as above.
- The Admin is the all mighty role for admins that can do what any sub-role
- can do and more.
- Then we have the Site-Admin that can monitor the application, the User-Admin
- that can manage users, then Romania-Admin that can manage users from Romania,
- US-Admin that can manage users from US and UK-Admin that can only manage
- users from UK.
- Now a User-Admin can manage users from anywhere but a Site-Admin can not
- manage any users.
- Neither a Romania-Admin has the priviledges of User-Admin or Admin, nor
- it can manage the US or UK users.
- You got the picture here; the idea is that the lower a Role is in the hierarchy
- the less priviledged it is.
- Let'see how the code looks like based on the above figure:
+ shows how we could do this in PocketChange if we modified the
+\family typewriter
+User.password
+\family default
+ field to simply be a
+\family typewriter
+MappedString
+\family default
+.
\end_layout
\begin_layout Standard
@@ -3921,7 +4266,14 @@ status open
\begin_inset Caption
\begin_layout Plain Layout
-HTTP Authentication multi-roles example
+Performing Digest Authentication
+\begin_inset CommandInset label
+LatexCommand label
+name "lst:HTTP-Digest-Authentication"
+
+\end_inset
+
+
\end_layout
\end_inset
@@ -3931,140 +4283,227 @@ HTTP Authentication multi-roles example
\begin_layout Plain Layout
-import auth._
+import net.liftweb.http.auth.{AuthRole,HttpBasicAuthentication,userRoles}
\end_layout
\begin_layout Plain Layout
+LiftRules.authentication = HttpBasicAuthentication("PocketChange") {
\end_layout
\begin_layout Plain Layout
-class Boot {
+ case (userEmail, _, authenticates) => {
\end_layout
\begin_layout Plain Layout
- def boot = {
+ logger.debug("Authenticating: " + userEmail)
\end_layout
\begin_layout Plain Layout
- ...
+ User.find(By(User.email, userEmail)).map { user =>
\end_layout
\begin_layout Plain Layout
+ if (authenticates(user.password.is)) {
\end_layout
\begin_layout Plain Layout
- val roles = AuthRole("Admin",
+ logger.debug("Auth succeeded for " + userEmail)
\end_layout
\begin_layout Plain Layout
- AuthRole("Site-Admin"),
+ User.logUserIn(user)
\end_layout
\begin_layout Plain Layout
- AuthRole("User-Admin",
\end_layout
\begin_layout Plain Layout
- AuthRole("Romania-Admin"),
+ // Compute all of the user roles
\end_layout
\begin_layout Plain Layout
- AuthRole("US-Admin"),
+ userRoles(user.editable.map(acct => AuthRole("editAcct:" + acct.id))
+ ++
\end_layout
\begin_layout Plain Layout
- AuthRole("UK-Admin")
+ user.allAccounts.map(acct => AuthRole("viewAcct:" + acct.id)))
\end_layout
\begin_layout Plain Layout
- )
+ true
\end_layout
\begin_layout Plain Layout
- )
+ } else {
\end_layout
\begin_layout Plain Layout
- LiftRules.protectedResource.append {
+ logger.warn("Auth failed for " + userEmail)
\end_layout
\begin_layout Plain Layout
- case (ParsePath("users" :: _, _, _, _)) => roles.getRoleByName("Romania-Adm
-in")
+ false
\end_layout
\begin_layout Plain Layout
- }
+ }
\end_layout
\begin_layout Plain Layout
-
+ } openOr false
\end_layout
\begin_layout Plain Layout
- LiftRules.authentication = HttpBasicAuthentication("lift") {
+ }
\end_layout
\begin_layout Plain Layout
- case ("John", "12test34", req) =>
+}
\end_layout
-\begin_layout Plain Layout
+\end_inset
+
- println("John is authenticated !")
\end_layout
+\begin_layout Standard
+Another important factor with Digest authentication is that it uses nonces
+\begin_inset Foot
+status open
+
\begin_layout Plain Layout
+\begin_inset Flex URL
+status open
- userRoles(AuthRole("User-Admin"))
+\begin_layout Plain Layout
+
+http://en.wikipedia.org/wiki/Cryptographic_nonce
\end_layout
-\begin_layout Plain Layout
+\end_inset
+
- true
\end_layout
-\begin_layout Plain Layout
+\end_inset
- }
+ for authenticating the client, and the nonces have a limited lifetime.
+ The default nonce lifetime is 30 seconds, but you can configure this by
+ overriding the
+\family typewriter
+HttpDigestAuthentication.nonceValidityPeriod
+\family default
+ method.
\end_layout
-\begin_layout Plain Layout
+\begin_layout Subsection
+Role Hierarchies
+\begin_inset CommandInset label
+LatexCommand label
+name "sub:Role-Hierarchies"
+
+\end_inset
+
\end_layout
-\begin_layout Plain Layout
+\begin_layout Standard
+So far we've discussed
+\family typewriter
+Role
+\family default
+s as essentially flat constructs.
+ A
+\family typewriter
+Role
+\family default
+, however, is an n-ary tree structure, meaning that when we assign a
+\family typewriter
+Role
+\family default
+ to a protected resource we can actually provide a hierarchy.
+ Figure
+\begin_inset CommandInset ref
+LatexCommand ref
+reference "fig:Roles-hierarchy-example"
- ...
+\end_inset
+
+ shows an example of one such hierarchy.
+ In this example, the Admin is the
+\begin_inset Quotes eld
+\end_inset
+
+superuser
+\begin_inset Quotes erd
+\end_inset
+
+ role for admins, and can do what any sub-role can do and more.
+ The Site-Admin can monitor the application, the User-Admin can manage users,
+ and then we specify a set of location-specific roles: the Romania-Admin
+ that can manage users from Romania, US-Admin that can manage users from
+ US and UK-Admin that can only manage users from UK.
+ With this hierarchy a User-Admin can manage users from anywhere but a Site-Admi
+n can not manage any users.
+ A Romania-Admin can't monitor the site, nor it can manage the US or UK
+ users.
\end_layout
+\begin_layout Standard
+\begin_inset Float figure
+wide false
+sideways false
+status open
+
\begin_layout Plain Layout
+\align center
+\begin_inset Graphics
+ filename images/roles.png
+ lyxscale 10
+ width 5in
+
+\end_inset
+
- }
\end_layout
\begin_layout Plain Layout
+\begin_inset Caption
+
+\begin_layout Plain Layout
+Roles hierarchy example
+\begin_inset CommandInset label
+LatexCommand label
+name "fig:Roles-hierarchy-example"
+
+\end_inset
+
+
+\end_layout
+
+\end_inset
+
-}
\end_layout
\end_inset
@@ -4073,52 +4512,46 @@ in")
\end_layout
\begin_layout Standard
-In this case if user is authenticated, authorization will also succeed because
- the user's Role is User-Admin and it is a parent of
+Given this Role hierarchy, Listing
+\begin_inset CommandInset ref
+LatexCommand ref
+reference "lst:Using-Role-Hierarchies"
+
+\end_inset
+
+ shows how we can implement this in our code by creating our Role hierarchy
+ and then using the Role.getRoleByName method to locate the proper Role when
+ we perform authentication.
+ In this example we're restricting access to the
+\family typewriter
+/users/ro
+\family default
+ path to only users with the
\begin_inset Quotes eld
\end_inset
Romania-Admin
\begin_inset Quotes erd
\end_inset
-.
- If the /users resource would have been assigned with
+ role.
+ However, our fictional
\begin_inset Quotes eld
\end_inset
-User-Admin
+John
\begin_inset Quotes erd
\end_inset
- role and user John would have
+ user is assigned the
\begin_inset Quotes eld
\end_inset
-Romania-Admin
+User-Admin
\begin_inset Quotes erd
\end_inset
- role that even if credentials are correct the authorization fails hence
- a 401 HTTP status is still sent to client.
-\end_layout
-
-\begin_layout Standard
-In conclusion you have a simple authentication and authorization mechanism
- and of course authentication function would typically validate the credentials
- against a database and fetch the roles from there.
-\end_layout
-
-\begin_layout Subsubsection
-HTTP Digest Authentication
-\end_layout
-
-\begin_layout Standard
-So far we talked about basic authentication and authorization.
- Lift also support HTTP Digest authentication.
- This means that the password information that user enters in the browser
- is never propagated on the server.
- Here is how we use it:
+ role, so he will be able to access that path.
\end_layout
\begin_layout Standard
@@ -4131,7 +4564,14 @@ status open
\begin_inset Caption
\begin_layout Plain Layout
-HTTP Digest Authentication multi-roles example
+Using Role Hierarchies
+\begin_inset CommandInset label
+LatexCommand label
+name "lst:Using-Role-Hierarchies"
+
+\end_inset
+
+
\end_layout
\end_inset
@@ -4165,11 +4605,12 @@ class Boot {
\begin_layout Plain Layout
+ val roles =
\end_layout
\begin_layout Plain Layout
- val roles = AuthRole("Admin",
+ AuthRole("Admin",
\end_layout
\begin_layout Plain Layout
@@ -4179,7 +4620,7 @@ class Boot {
\begin_layout Plain Layout
- AuthRole("User-Admin",
+ AuthRole("User-Admin",
\end_layout
\begin_layout Plain Layout
@@ -4209,73 +4650,61 @@ class Boot {
\begin_layout Plain Layout
- LiftRules.protectedResource.append {
-\end_layout
-
-\begin_layout Plain Layout
-
- case (ParsePath("users" :: _, _, _, _)) => roles.getRoleByName("Romania-Adm
-in")
\end_layout
\begin_layout Plain Layout
- }
-\end_layout
-
-\begin_layout Plain Layout
-
-
+ LiftRules.protectedResource.append {
\end_layout
\begin_layout Plain Layout
- LiftRules.authentication = HttpDigestAuthentication("lift") {
+ case (ParsePath("users" :: "ro" :: _, _, _, _)) => roles.getRoleByName("Rom
+ania-Admin")
\end_layout
\begin_layout Plain Layout
- case ("John", req, func) => if (func("12test34")) {
+ }
\end_layout
\begin_layout Plain Layout
- println("John is authenticated !")
+
\end_layout
\begin_layout Plain Layout
- userRoles(AuthRole("useradmin"))
+ LiftRules.authentication = HttpBasicAuthentication("lift") {
\end_layout
\begin_layout Plain Layout
- true
+ case ("John", "12test34", req) =>
\end_layout
\begin_layout Plain Layout
- } else {
+ println("John is authenticated !")
\end_layout
\begin_layout Plain Layout
- println("Not verified")
+ userRoles(AuthRole("User-Admin"))
\end_layout
\begin_layout Plain Layout
- false
+ true
\end_layout
\begin_layout Plain Layout
- }
+ }
\end_layout
\begin_layout Plain Layout
- }
\end_layout
\begin_layout Plain Layout
@@ -4298,101 +4727,5 @@ in")
\end_layout
-\begin_layout Standard
-Eveything we talked about Roles is still valid.
- However we're now using digest authentication.
- Note that in this case we're not provided with a password anymore but our
- function is provided with the user name, the Req object and a callback
- function.
- Because digest authentication implies checksum calculations there is no
- need to burden the user with such things.
- However our code calls this callback function by providing the password
- (which can be retrieved from database as we know the user name).
- If this function returns true it means that the digest that client sent
- andthe one that Lift calculated matches so we have a successful authentication.
-
-\end_layout
-
-\begin_layout Standard
-There is also important to know that diget authentication mechanism uses
- a nonce sequence.
- This sequence is generated by the server when sending down the authentication
- challenge down to client (401 HTTP status).
- In order to avoid replay attacks this nonce is valid only for a period
- of time.
- By default this is set to 30 seconds but you can change this by setting:
-\end_layout
-
-\begin_layout Standard
-
-\family typewriter
-HttpDigestAuthentication.nonceValidityPeriod = <a value in milliseconds>
-\end_layout
-
-\begin_layout Standard
-If you use Lift's TimeHelpers you can say:
-\end_layout
-
-\begin_layout Standard
-
-\family typewriter
-HttpDigestAuthentication.nonceValidityPeriod = 50 seconds
-\end_layout
-
-\begin_layout Standard
-
-\family typewriter
-// where seconds is a function and there are implicit conversion functions
- from
-\begin_inset Quotes eld
-\end_inset
-
-primitives
-\begin_inset Quotes erd
-\end_inset
-
- to TimeSpans type.
-\end_layout
-
-\begin_layout Standard
-If this period expires even if the authentication and authorization succeed
- Lift will challenge it again by returning 401 HTTP status and a new nonce.
- So the resource is not served yet.
-\end_layout
-
-\begin_layout Standard
-It is important to know that a user can be assigned with multiple roles,
- not just one.
- This can be done by calling:
-\end_layout
-
-\begin_layout Standard
-
-\family typewriter
-userRoles(AuthRole("US-Admin",
-\begin_inset Quotes eld
-\end_inset
-
-Site-Admin
-\begin_inset Quotes erd
-\end_inset
-
-)) // AuthRole overloaded apply function takes a repeated parameter.
-\end_layout
-
-\begin_layout Standard
-This is pretty much it as far as HTTP authentication and authorization goes
- but there is one more thing that is worth to be mentioned.
- If your application does not persist the user's password and only a digest
- internally calculated, the HTTP digest authentication can not really be
- used.
- The reason is that in order to match the client's digest, server needs
- to calculate it and for that it needs the password in clear but because
- the application stores a digest, the user's password can not be recovered.
- Hence the HTTP digest can not be calculated.
- This is a missmatch betwen the two concepts: HTTP digest authentication
- given by RFC 2617 and the unrecoverable password storage.
-\end_layout
-
\end_body
\end_document
View
17 chap-demoapp.lyx
@@ -44,6 +44,13 @@
\begin_layout Chapter
PocketChange
+\begin_inset CommandInset label
+LatexCommand label
+name "cha:PocketChange"
+
+\end_inset
+
+
\end_layout
\begin_layout Standard
@@ -155,9 +162,13 @@ Another important thing to note is that we're going to breeze through the
status open
\begin_layout Plain Layout
-\begin_inset CommandInset href
-LatexCommand href
-target "http://github.com/tjweir/pocketchangeapp/tree"
+\begin_inset Flex URL
+status open
+
+\begin_layout Plain Layout
+
+http://github.com/tjweir/pocketchangeapp
+\end_layout
\end_inset
View
12 chap-js_commands.lyx
@@ -1,4 +1,4 @@
-#LyX 1.6.5 created this file. For more info see http://www.lyx.org/
+#LyX 1.6.7 created this file. For more info see http://www.lyx.org/
\lyxformat 345
\begin_document
\begin_header
@@ -2534,6 +2534,16 @@ The basic application of the transformation from a NodeSeq to the JavaScript
\begin_layout Section
JSON
+\begin_inset Note Note
+status open
+
+\begin_layout Plain Layout
+Need to add details on lift-json as well
+\end_layout
+
+\end_inset
+
+
\end_layout
\begin_layout Standard
View
4 chap-sitemap.lyx
@@ -536,7 +536,7 @@ reference "sec:Customizing-Display"
,
\begin_inset CommandInset ref
LatexCommand ref
-reference "sec:Access-Control"
+reference "sec:SiteMap-Access-Control"
\end_inset
@@ -1663,7 +1663,7 @@ reference "sub:LocGroup"
Access Control
\begin_inset CommandInset label
LatexCommand label
-name "sec:Access-Control"
+name "sec:SiteMap-Access-Control"
\end_inset
View
243 chap-template_xhtml.lyx
@@ -1716,19 +1716,36 @@ name "sec:ArchTags"
In the earlier sections on Templates and Views we briefly touched on some
of Lift's built-in tags, namely,
\family typewriter
-snippet
+<lift:snippet/>
\family default
and
\family typewriter
-surround
+<lift:surround
\family default
-.
+/>.
In this section we'll go into more detail on those tags as well as cover
the rest of Lift's tags.
\end_layout
\begin_layout Subsection
a
+\begin_inset CommandInset label
+LatexCommand label
+name "sub:a-tag"
+
+\end_inset
+
+
+\begin_inset Index
+status open
+
+\begin_layout Plain Layout
+Tags ! a
+\end_layout
+
+\end_inset
+
+
\begin_inset Index
status open
@@ -1756,8 +1773,11 @@ The
\family typewriter
<lift:a/>
\family default
- tag is used internally by SHtml.a to create an anchor tag that will call
- an AJAX function when clicked.
+ tag is used internally by
+\family typewriter
+SHtml.a
+\family default
+ to create an anchor tag that will call an AJAX function when clicked.
This tag is generally not used directly by developers.
See Section
\begin_inset CommandInset ref
@@ -1771,12 +1791,9 @@ reference "sub:AJAX-Generators-in-detail"
\begin_layout Subsection
bind
-\begin_inset Index
-status open
-
-\begin_layout Plain Layout
-bind
-\end_layout
+\begin_inset CommandInset label
+LatexCommand label
+name "sub:bind-tag"
\end_inset
@@ -1791,9 +1808,12 @@ Tags ! bind
\end_inset
-\begin_inset CommandInset label
-LatexCommand label
-name "sub:bind-tag"
+\begin_inset Index
+status open
+
+\begin_layout Plain Layout
+binding
+\end_layout
\end_inset
@@ -1817,88 +1837,57 @@ The
\family typewriter
<lift:bind/>
\family default
- tag is the counterpart to the
+ tag is used as a placeholder for insertion of content within included templates
+ when using the
\family typewriter
-<lift:surround/>
+<lift:surround/> and
\family default
- tag: it specifies where in the
-\begin_inset Quotes eld
-\end_inset
-
-surrounding
-\begin_inset Quotes erd
-\end_inset
-
- template the content will be placed.
- An example is shown in Listing
+
+\family typewriter
+<lift:embed/>
+\family default
+ tags.
+ See Section
\begin_inset CommandInset ref
LatexCommand ref
-reference "lst:Binding-in-Templates"
+reference "sec:Binding"
\end_inset
-.
+ for examples and discussion.
\end_layout
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-\begin_inset Caption
-
-\begin_layout Plain Layout
-Binding in Templates
+\begin_layout Subsection
+bind-at
\begin_inset CommandInset label
LatexCommand label
-name "lst:Binding-in-Templates"
+name "sub:bind-at-tag"
\end_inset
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Plain Layout
-
-<html>
-\end_layout
+\begin_inset Index
+status open
\begin_layout Plain Layout
-
- <body>
+Tags ! bind-at
\end_layout
-\begin_layout Plain Layout
-
- <lift:bind name="content" />
-\end_layout
+\end_inset
-\begin_layout Plain Layout
- </body>
-\end_layout
+\begin_inset Index
+status open
\begin_layout Plain Layout
-
-</html>
+binding
\end_layout
\end_inset
\end_layout
-\begin_layout Subsection
-bind-at
-\end_layout
-
\begin_layout LyX-Code
Usage: <lift:bind-at name=
\begin_inset Quotes erd
@@ -1912,19 +1901,42 @@ binding_name
\end_layout
\begin_layout Standard
-The bind-at tag is used in conjunction with
+The
+\family typewriter
+<lift:bind-at/>
+\family default
+ tag is used to replace named
\family typewriter
<lift:bind/>
\family default
- and
+ tags within
\family typewriter
<lift:surround/>
\family default
- to allow additional named sections to be placed withing a surrounding template.
+ and
+\family typewriter
+<lift:embed/>
+\family default
+ tags.
+ See Section
+\begin_inset CommandInset ref
+LatexCommand ref
+reference "sec:Binding"
+
+\end_inset
+
+ for examples and discussion.
\end_layout
\begin_layout Subsection
children
+\begin_inset CommandInset label
+LatexCommand label
+name "sub:children-tag"
+
+\end_inset
+
+
\begin_inset Index
status open
@@ -1954,7 +1966,7 @@ Usage: <lift:children>...multiple xml nodes here...</lift:children>
\begin_layout Standard
The purpose of the
\family typewriter
-children
+<lift:children/>
\family default
tag is to allow you to create fragment templates with more than one root
element that still parse as valid XML.
@@ -2083,6 +2095,13 @@ name "lst:A-Conforming-XML"
\begin_layout Subsection
comet
+\begin_inset CommandInset label
+LatexCommand label
+name "sub:comet-tag"
+
+\end_inset
+
+
\begin_inset Index
status open
@@ -2122,7 +2141,7 @@ optional
\begin_layout Standard
The
\family typewriter
-comet
+<lift:comet/>
\family default
tag embeds a Comet actor into your page.
The class of the Comet actor is specified by the
@@ -2224,7 +2243,7 @@ name "lst:Ledger-Entry-Comet"
\end_layout
\begin_layout Standard
-As we mentioned in the
+As we mention in the
\family typewriter
embed
\family default
@@ -2234,6 +2253,69 @@ embed
\begin_layout Subsection
CSS
+\begin_inset CommandInset label
+LatexCommand label
+name "sub:CSS-tag"
+
+\end_inset
+
+
+\begin_inset Index
+status open
+
+\begin_layout Plain Layout
+Tags ! CSS
+\end_layout
+
+\end_inset
+
+
+\begin_inset Index
+status open
+
+\begin_layout Plain Layout
+CSS
+\end_layout
+
+\end_inset
+
+
+\end_layout
+
+\begin_layout LyX-Code
+Usage: <lift:CSS.blueprint />
+\end_layout
+
+\begin_layout LyX-Code
+ <lift:CSS.fancyType />
+\end_layout
+
+\begin_layout Standard
+The
+\family typewriter
+<lift:CSS/>
+\family default
+ tag is used to insert either the blueprint
+\begin_inset Foot
+status open
+
+\begin_layout Plain Layout
+\begin_inset Flex URL
+status open
+
+\begin_layout Plain Layout
+
+http://www.blueprintcss.org/
+\end_layout
+
+\end_inset
+
+
+\end_layout
+
+\end_inset
+
+ or fancy
\end_layout
\begin_layout Subsection
@@ -2827,10 +2909,10 @@ XmlGroup
\end_layout
\begin_layout Section
-Head Merge
+Head and Tail Merge
\begin_inset CommandInset label
LatexCommand label
-name "sec:Head-Merge"
+name "sec:Head-Tail-Merge"
\end_inset
@@ -2845,7 +2927,7 @@ head
\family default
\begin_inset Index
-status collapsed
+status open
\begin_layout Plain Layout
head
@@ -2950,5 +3032,16 @@ name "lst:Using-Head-Merge"
In this manner, you'll import TableSorter for this template alone.
\end_layout
+\begin_layout Section
+Binding
+\begin_inset CommandInset label
+LatexCommand label
+name "sec:Binding"
+
+\end_inset
+
+
+\end_layout
+
\end_body
\end_document
View
3,096 chap-web_services.lyx
2,515 additions, 581 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
View
35 chap-welcome.lyx
@@ -407,6 +407,41 @@ General HTTP processing, including GET and POST submission, response codes,
\end_layout
\begin_layout Section
+Typographical Conventions
+\end_layout
+
+\begin_layout Standard
+In order to better communicate concepts and techniques in this book, we
+ have adopted the following typographical conventions:
+\end_layout
+
+\begin_layout List
+\labelwidthstring 00.00.0000
+
+\family typewriter
+ClassName
+\family default
+ Monospaced typewriter text is used to indicate types, class names, and
+ other code-related information.
+\end_layout
+
+\begin_layout List
+\labelwidthstring 00.00.0000
+...
+ Ellipses within code listings are used to indicate omission of code to
+ condense listings.
+ Unless otherwise noted, the example code in this book comes from the PocketChan
+ge app (Chapter
+\begin_inset CommandInset ref
+LatexCommand vref
+reference "cha:PocketChange"
+
+\end_inset
+
+), which has full source code available on GitHub.
+\end_layout
+
+\begin_layout Section
For More Information about Lift
\begin_inset CommandInset label
LatexCommand label

0 comments on commit 76b71e0

Please sign in to comment.