From cfe257781b4a5069f29801ab43587f6aedcdffd0 Mon Sep 17 00:00:00 2001 From: Chas Emerick Date: Fri, 6 Apr 2012 19:23:30 -0400 Subject: [PATCH] OMG documentation --- README.md | 302 ++++++++++++++++++---- workflow.graffle => docs/workflow.graffle | 25 +- docs/workflow.png | Bin 0 -> 46013 bytes project.clj | 11 +- test/test_friend/mock_app.clj | 24 +- 5 files changed, 281 insertions(+), 81 deletions(-) rename workflow.graffle => docs/workflow.graffle (98%) create mode 100644 docs/workflow.png diff --git a/README.md b/README.md index 25a4697..102c06d 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Friend -An authentication and authorization library for +An extensible authentication and authorization library for [Clojure](http://clojure.org) [Ring](http://github.com/mmcgrana/ring) -applications and services. +applications and services. ``` Picking up his staff he stood before the rock and said in a clear voice: @@ -25,103 +25,294 @@ suspicious days. Those were happier times. Now let us go!" ``` — J.R.R. Tolkien, _Lord of the Rings_ -## "Installation" +## Overview -## Usage +Friend is intended to provide a foundation for addressing +all of the security concerns associated with web apps: -### Features +* channel security (restricting certain resources to a particular + protocol/scheme, usually HTTPS) +* user agent authentication; Friend currently includes support for form, + HTTP Basic, and OpenId authentication, and makes it easy to: + * implement and use other workflows + * integrate app-specific user-credential checks +* role-based authentication + * optionally uses Clojure's ad-hoc hierarchies to model hierarchical + roles +* `su` capabilities (a.k.a. "log in as"), enabling administrators to + easily take on user identities for debugging or support purposes (**in +progress**) +* and the creature comforts: + * Ring middlewares for configuring and defining the scopes of + authentication, authorization, and channel security + * Macros to clearly demarcate the scope of authentication and + authorization within code that is "below" the level of Ring handlers + where you can't use middlewares. + * A reasonable Clojure API around the jbcrypt library for hashing + sensitive bits. + * Enables DRY routes and configuration, e.g. no need to configure your + routes in Compojure or Noir or Moustache, and separately specify + which routes fall under the jurisdiction of Friend's security machinery + * Purely functional in nature: authentications, roles, and session + data are obtained, retained, and passed around as good ol' + persistent data structures (just as Ring intended). No stateful session + or context is ever bashed in place, making it easier to reason about + what's going on. + +### Why? + +Nothing like Friend exists, and it needs to. Securing Ring applications +and services is (charitably speaking) a PITA right now, with everyone +rolling their own, or starting with relatively low-level middlewares and +frameworks. This will never do. Serious web applications need to take +security seriously, and need to readily interoperate with all sorts of +authentication mechanisms that have come to litter the web as well as +internal networks. + +Friend has been built with one eye on a number of frameworks. + +* [warden](https://github.com/hassox/warden/wiki) +* [spring-security](http://static.springsource.org/spring-security/) +* [everyauth](https://github.com/bnoguchi/everyauth) +* [omniauth](https://github.com/intridea/omniauth) +* [sandbar](https://github.com/brentonashworth/sandbar) + +### Status + +Friend is brand-spanking-new. It's also obviously involved in security +matters. While it's hardly untested, and _is_ in use in production, +it's obviously not seen the kind of beating and vetting that established +security libraries and frameworks have had (i.e. spring-security, JAAS +stuff, etc). + +So, proceed happily, but mindfully. Only with your help will we have a +widely-tested Ring application security library. + +### Known issues + +* Configuration keys need a bit of tidying, especially for those that + can/should apply to multiple authorization workflows. Fixes for such +things will break the existing API. +* the `su` mechanism is in-progress +* the OpenId authentication workflow needs to be broken out into a + separate project so that those who aren't using it don't suffer its +transitive dependencies. (The form and HTTP Basic workflows are +dependency-free, and will likely remain here.) +* …surely there's more. File issues. + +## "Installation" -#### Channel security +Friend is available in Clojars. Add this `:dependency` to your Leiningen +`project.clj`: ```clojure -(use '[cemerick.friend :only (requires-scheme *default-scheme-ports*)]) +[com.cemerick/friend "0.0.1"] +``` -(def https-routes (requires-scheme routes :https)) +Or, add this to your Maven project's `pom.xml`: -(def http-routes (requires-scheme routes :http)) +```xml + + clojars + http://clojars.org/repo + -(def custom-https-port-routes (requires-scheme routes :https {:https 8443})) + + com.cemerick + friend + 0.0.1 + +``` -(binding [*default-scheme-ports* {:http 8080 :https 8443}] - (def http-routes (requires-scheme routes :http)) - (def https-routes (requires-scheme routes :https))) +Friend is compatible with Clojure 1.2.0 - 1.4.0. + +## Usage + +There is a fairly ornate Ring application +[here](test/test_friend/mock_app.clj) that is the basis for Friend's +functional tests that you can look at. That's likely a little hard to +navigate though, so a simpler introduction is worthwhile. + +Here's probably the most self-contained Friend usage possible: + +```clojure +(ns your.ring.app + (:require [cemerick.friend :as friend] + (cemerick.friend [workflows :as workflows] + [credentials :as creds]))) + +; a dummy in-memory user "database" +(def users {"root" {:username "root" + :password (creds/hash-bcrypt "admin_password") + :roles #{::admin}} + "jane" {:username "jane" + :password (creds/hash-bcrypt "user_password") + :roles #{::user}}}) + +(def ring-app ; ... assemble routes however you like ... + ) + +(def secured-app + (->> ring-app + (friend/authenticate {:credential-fn (partial creds/bcrypt-credential-fn users) + :workflows [(workflows/interactive-form)]}) + ; ...required Ring middlewares ... + )) ``` -#### Credential functions +We have an unadorned (and unsecured) Ring application (`ring-app`, which +can be any Ring handler), and then the usage of Friend's `authenticate` +middleware. This is where all of the authentication work will be done, +with the return value being a secured Ring application (`secured-app`), +the requests to which are subject to the configuration provided to +`authenticate` and the authorization contexts that are defined within +`ring-app` (which we'll get to shortly). -Workflows use a credential function to verify the credentials provided to them. -Credential functions can be specified either as a `:credential-fn` option to -`cemerick.friend/authenticate`, or often as (an overriding) `:credential-fn` -option to individual workflow functions. +There are two key abstractions employed during authentication: workflows +and credential functions. -All credential functions take a single argument, a map containing the available -credentials, and hopefully a `:cemerick.friend/workflow` slot identifying which -workflow has produced the credential. For example, the default form-based -authentication credential map looks like this: +(Note that Friend itself requires some core Ring middlewares: `params`, +`keyword-params` and `nested-params`. Most workflows will additionally +require `session` in order to support post-authentication redirection to +previously-unauthorized resources, retention of tokens and nonces for +workflows like OpenId and oAuth, etc. HTTP Basic is the only provided +workflow that does not require `session` middleware.) + +### Workflows + +Individual authentication methods (e.g., form-based auth, HTTP Basic, OpenID, +oAuth, etc.) are implemented as _workflows_ in Friend. A workflow is a +regular Ring handler function, except that a workflow function can _opt_ +to return an _authentication map_ instead of a Ring response if a +request is authenticated. A diagram may help: + +![](https://github.com/cemerick/friend/raw/master/docs/workflow.png) + +You can define any number of workflows in a `:workflows` kwarg to +`authenticate`. Incoming requests are always run through the configured +workflows prior to potentially being passed along to the secured Ring +application. + +If a workflow returns an authentication map, then the `authenticate` +middleware will either: + +* carry on processing the request if the workflow allows for credentials + to be provided in requests to any resource (i.e. HTTP Basic); control + of this is entirely up to each workflow, and will be described later. +* redirect the user agent to a secured resource that it was previously + barred from accessing via Friend's authorization machinery + +If a workflow returns a Ring response, then that response is sent back +to the user agent straight away (after some bookkeeping by the +`authenticate` middleware to preserve session states and such). This +makes it possible for a workflow to control a "local" dataflow between +itself, the user agent, and any necessary external authorities (e.g. by +redirecting a user agent to an OpenId endpoint, performing token +exchange in the case of oAuth, etc., eventually returning a complete +authentication map that will allow the user agent to proceed on its +desired vector). + +### Credential functions and authentication maps + +Workflows use a _credential function_ to verify the credentials provided +to them via requests. Credential functions can be specified either as a +`:credential-fn` option to `cemerick.friend/authenticate`, or often as +an (overriding) `:credential-fn` option to individual workflow +functions. + +All credential functions take a single argument, a map containing the +available credentials that additionally contains a +`:cemerick.friend/workflow` slot identifying which workflow has produced +the credential. For example, the default form-based authentication +credential map looks like this: ```clojure -{:username "…" :password "…" :cemerick.friend/workflow :form} +{:username "...", :password "...", :cemerick.friend/workflow :form} ``` HTTP Basic credentials are much the same, but with a workflow value of `:http-basic`, etc. Different workflows may have significantly different -credential maps (e.g. an OpenID workflow would not provide username and -password, but rather a token returned by an OpenID provider). +credential maps (e.g. an OpenID workflow does not provide username and +password, but rather a token returned by an OpenID provider along with +potentially some number of "attributes" like the user's name, email +address, default language, etc.), and unique credential verification +requirements (again, contrast the simple username/password verification +of form or HTTP Basic credentials and OpenId, which, in +general, when presented with unknown credentials, should _register_ the +indicated identity rather than verifying it). + +In summary, the contract of what exactly must be in the map provided to +credential functions is entirely at the discretion of each workflow +function, as is the semantics of the credential function. If a map of credentials is verified by a credential function, it should return a _authentication map_ that aggregates all authentication and authorization information available for the identified user. This map may contain many entries, depending upon the authentication information that is relevant for the -workflow in question and the user data relevant to the application: +workflow in question and the user data relevant to the application, but two entries are priviliged: * `:identity` (**required**) corresponds with e.g. the username in a form or - HTTP Basic authentication, an oAuth token, etc. -* `:roles`, an optional set of values enumerating the roles for which the user + HTTP Basic authentication, an oAuth token, etc.; this value _must_ be + unique across all users within the application +* `:roles`, an optional collection of values enumerating the roles for which the user is authorized. -If a map of credentials is found to be invalid, the credential function must -return nil. +_If a map of credentials is found to be invalid, the credential function must +return nil._ -#### Authentication retention (or not) +### Authentication retention (or not) +### Authorization +#### Simple vs. hierarchical roles -#### Logout +### Channel security -Logging a user out is accomplished by directing the user to a route that -has had `cemerick.friend/logout` middleware applied to it: +_Channel security_ is the redirection of requests for a given resource +through a specific channel, i.e. requiring that logins or a payment +workflow is performed over HTTPS instead over HTTP. + +`requires-scheme` is Ring middleware that enforces channel security for +a given Ring handler: ```clojure -(use '[cemerick.friend :only (logout)]) -(def logout-route (logout logout-handler)) -``` +(use '[cemerick.friend :only (requires-scheme *default-scheme-ports*)]) +; HTTP requests routed to https-routes will be redirected to the +; corresponding HTTPS URL on the default port +(def https-routes (requires-scheme routes :https)) -`:cemerick.friend/auth` entry from their session. You can do this manually, or -use the `logout` middleware to ensure that that entry +; HTTP requests routed to custom-https-port-routes be redirected to the +; corresponding HTTPS URL on port 8443 +(def custom-https-port-routes (requires-scheme routes :https {:https 8443})) +; alternative default ports for HTTP and HTTPS may be bound dynamically +; to simplify configuration of multiple routes +(binding [*default-scheme-ports* {:http 8080 :https 8443}] + (def http-routes (requires-scheme routes :http)) + (def https-routes (requires-scheme routes :https))) +``` -#### Workflows +Note that `requires-scheme` is unrelated to the authentication, +authorization, etc facilities in Friend, and can be used in isolation. + +## TODO -Individual authentication methods (e.g., form-based auth, HTTP Basic, OpenID, -oAuth, etc.) are implemented as _workflows_ in Friend. A workflow is a regular -Ring handler function, except that, rather than potentially returning a Ring -response, a workflow function can opt to return an authentication map if a -request has been authenticated fully. - -* salts -* crypts/ciphers -* remember-me -* role-based authentication * run-as/sudo/multi-user login +* alternative hashing methods and salting strategies + * good to encourage bcrypt, but existing apps have tons of sha-X, md5, + etc passwords +* remember-me? * interop * recognize / provide access to servlet principal * spring-security - -## TODO - -* use hierarchies and `isa?` instead of sets of simple values for - authorization +* make `:cemerick.friend/workflow` metadata +* documentation + * authentication map metadata: + * `:type` + * `::friend/workflow` + * `::friend/transient` + * `::friend/redirect-on-auth?` ## Need Help? @@ -134,3 +325,4 @@ like to contribute patches. Copyright ©2012 [Chas Emerick](http://cemerick.com) Distributed under the Eclipse Public License, the same as Clojure. +Please see the `epl-v10.html` file at the top level of this repo. diff --git a/workflow.graffle b/docs/workflow.graffle similarity index 98% rename from workflow.graffle rename to docs/workflow.graffle index ba11b9f..1d5346c 100644 --- a/workflow.graffle +++ b/docs/workflow.graffle @@ -31,7 +31,7 @@ Bounds - {{188.03281, 252.90768}, {32, 13}} + {{190.03989, 251.922}, {32, 13}} Class ShapedGraphic FitText @@ -55,9 +55,9 @@ ID 378 Offset - -7 + -8 Position - 0.57173967361450195 + 0.54317331314086914 RotationType 0 @@ -95,6 +95,13 @@ Class LineGraphic + FontInfo + + Font + Helvetica + Size + 10 + Head ID @@ -114,11 +121,13 @@ stroke HeadArrow - FilledArrow + StickArrow HopLines HopType 1 + Pattern + 1 TailArrow 0 @@ -779,7 +788,9 @@ stroke Pattern - 1 + 11 + Width + 2 Text @@ -924,7 +935,7 @@ ModificationDate - 2012-03-26 19:40:09 +0000 + 2012-04-06 22:33:36 +0000 Modifier Chas Emerick NotesVisible @@ -996,7 +1007,7 @@ FitInWindow Frame - {{585, 116}, {603, 874}} + {{316, 4}, {603, 874}} ShowRuler ShowStatusBar diff --git a/docs/workflow.png b/docs/workflow.png new file mode 100644 index 0000000000000000000000000000000000000000..56fb7520dd8f0bb57d8ad30eb930e7ebdaf7f387 GIT binary patch literal 46013 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 literal 0 HcmV?d00001 diff --git a/project.clj b/project.clj index aacb08b..d527c4b 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject com.cemerick/friend "0.0.1-SNAPSHOT" +(defproject com.cemerick/friend "0.0.1" :description "Authentication and authorization library for Ring Clojure web apps and services." :url "http://github.com/cemerick/friend" :license {:name "Eclipse Public License" @@ -14,7 +14,7 @@ [commons-codec "1.6"] ;; openid - [org.openid4java/openid4java-consumer "0.9.6" :type "pom"] + [org.openid4java/openid4java-consumer "0.9.6" :extension "pom"] ; need different httpclient rev for https://issues.apache.org/jira/browse/HTTPCLIENT-1118 [org.apache.httpcomponents/httpclient "4.2-beta1"]] :profiles {:dev {:dependencies [[ring-mock "0.1.1"] @@ -23,7 +23,7 @@ [clj-http "0.3.6-SNAPSHOT"]]} :1.2 {:dependencies [[org.clojure/clojure "1.2.0"]]} :1.4 {:dependencies [[org.clojure/clojure "1.4.0-beta5"]]}} - + :aliases { "all" ["with-profile" "dev,1.2:dev:dev,1.4"] } :dev-dependencies [[ring-mock "0.1.1"] [compojure "1.0.1"] @@ -31,11 +31,8 @@ [clj-http "0.3.6-SNAPSHOT"]]) ;; see: -;; https://github.com/hassox/warden/wiki ;; http://static.springsource.org/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#overall-architecture -;; https://github.com/bnoguchi/everyauth -;; https://github.com/intridea/omniauth -;; https://github.com/brentonashworth/sandbar + ;; oauth ; https://github.com/DerGuteMoritz/clj-oauth2 OR diff --git a/test/test_friend/mock_app.clj b/test/test_friend/mock_app.clj index 6eaa1bd..32b13a4 100644 --- a/test/test_friend/mock_app.clj +++ b/test/test_friend/mock_app.clj @@ -7,8 +7,7 @@ [robert.hooke :as hooke] [hiccup.core :as hiccup] [ring.util.response :as resp] - (compojure [route :as route] - [handler :as handler])) + (compojure [handler :as handler])) (:use [compojure.core :as compojure :only (GET ANY defroutes)])) @@ -97,14 +96,15 @@ (def mock-app (->> authorization-config - (friend/authenticate {:credential-fn (partial creds/bcrypt-credential-fn users) - :unauthorized-redirect-uri "/login" - :login-uri "/login" - :workflows [(workflows/interactive-form - :login-uri "/login") - (workflows/http-basic - :credential-fn (partial creds/bcrypt-credential-fn api-users) - :realm mock-app-realm) - ;; TODO move openid test into its own ns - (openid/workflow :credential-fn (comp ring.util.response/response pr-str))]}) + (friend/authenticate + {:credential-fn (partial creds/bcrypt-credential-fn users) + :unauthorized-redirect-uri "/login" + :login-uri "/login" + :workflows [(workflows/interactive-form + :login-uri "/login") + (workflows/http-basic + :credential-fn (partial creds/bcrypt-credential-fn api-users) + :realm mock-app-realm) + ;; TODO move openid test into its own ns + (openid/workflow :credential-fn (comp ring.util.response/response pr-str))]}) handler/site))