anchor.diff:  git clone https://github.com/niwibe/buddy
   ----
   
  -
  -Core library
  -------------
  +Common Web Security
  +-------------------
  +
  +Generic Message Signing
  +~~~~~~~~~~~~~~~~~~~~~~~
  +
  +The "signing framework" of _buddy_ is mainly based on django's
  +link:https://docs.djangoproject.com/en/1.6/topics/signing/[Cryptographic
  +signing] library but extended with various signing algorithms and cryptography
  +support.
  +
  +It can be used for several purposes:
  +
  +- Safety send/store signed or encrypted messages.
  +- Safely storing session data in cookies instead of a database (It prevents others from changing session content)
  +- Self contained token generation for use it on completely stateless token based authentication.
  +
  +NOTE: this library is used by one of authentication backends for implement token based stateless authentication.
  +
  +.Supported Algorithms
  +[options="header"]
  +|=====================================================================================
  +|Algorithm name     | Hash algorithms   | Keywords           | Priv/Pub Key?
  +|Elliptic Curve DSA | sha256, sha512    | `:es256`, `:es512` | Yes
  +|RSASSA PSS         | sha256, sha512    | `:ps256`, `:ps512` | Yes
  +|RSASSA PKCS1 v1_5  | sha256, sha512    | `:rs256`, `:rs256` | Yes
  +|HMAC               | sha256*, sha512   | `:hs256`, `:hs256` | No
  +|=====================================================================================
  +
  ++++*+++ indicates the default value.
  +
  +
  +[NOTE]
  +====
  +Only HMAC based algorithm supports plain text secret keys, If you want use
  +Digital Signature instead of hmac, you must have a key pair (public and private).
  +====
  +
  +
  +Using low level api
  +^^^^^^^^^^^^^^^^^^^
  +
  +There are four signing functions in *`buddy.sign.generic`* namespace: `sign`,
  +`unsign`, `loads` and `dumps`.
  +
  +`sign` and `unsign` are low level and work primarily with strings.
  +
  +.Unsigning previously signed data
  +[source,clojure]
  +----
  +(require '[buddy.sign.generic :refer [sign unsign]])
  +
  +;; Sign data
  +(def signed-data (sign "mystring" "my-secret-key"))
  +
  +;; signed-data should contain a string similar to:
  +;; "mystring:f08dd937a438f43639d34a345910148cb933ea8ea0c2c306e8733e0255677e3d:MTM..."
  +
  +;; Unsign previosly signed data
  +(def unsigned-data (unsign signed-data "my-secret-key"))
  +
  +;; unsigned-data should contain the original string: "mystring"
  +----
  +
  +The signing process consists of appending signatures to the original
  +string and separating the signature with a predefined separator (default
  +":" char).
  +
  +Each signature has a timestamp attached (with millisecond of accuracy) so you can
  +invalidate signed messages based on their age.
  +
  +.Invalidate signed data using timestamp
  +[source,clojure]
  +----
  +;; Unsign with maxago (15min)
  +(def unsigned-data (unsign signed-data "my-secret-key" {:maxago (* 60 15 1000)}))
  +
  +;; unsigned-data should contain a nil value if the signing date is
  +;; older than 15 min.
  +----
  +
  +
  +Protecting complex data structures
  +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  +
  +If you wish to protect a native data structure (hash-map, hash-set,
  +list, vector, etc...)  you can do so using the signing `dumps` and
  +`loads` functions.
  +
  +They accept the same parameters as their low level friends, but can also sign
  +more complex data.
  +
  +.Sign/Unsign Clojure hash-map
  +[source,clojure]
  +----
  +(require '[buddy.sign.generic :refer [dumps loads]])
  +
  +;; Sign data
  +(def signed-data (dumps {:userid 1} "my-secret-key"))
  +
  +;; signed-data should contain a string similar to:
  +;; "TlBZARlgGwAAAAIOAAAABnVzZXJpZCsAAAAAAAAAAQ:59d9e8063ad80f6abd3092b45857810b10f5..."
  +
  +;; Unsign previously signed data
  +(def unsigned-data (loads signed-data "my-secret-key"))
  +
  +;; unsigned-data should contain a original map: {:userid 1}
  +----
  +
  +NOTE: it uses a Clojure serialization library link:https://github.com/ptaoussanis/nippy[Nippy]
  +
  +
  +Using Digital Signature algorithms
  +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  +
  +For use anyone of digital signature algorithms you must have a private/public key. If you
  +don't have one, don't worry - it's very easy to generate one using *openssl*.
  +
  +
  +Elliptic Curve DSA
  +++++++++++++++++++
  +
  +[source, bash]
  +----
  +# Generating params file
  +openssl ecparam -name prime256v1 -out ecparams.pem
  +
  +# Generate a private key from params file
  +openssl ecparam -in ecparams.pem -genkey -noout -out ecprivkey.pem
  +
  +# Generate a public key from private key
  +openssl ec -in ecprivkey.pem -pubout -out ecpubkey.pem
  +----
  +
  +
  +RSA based signatures
  +++++++++++++++++++++
  +
  +[source, bash]
  +----
  +# Generate aes256 encrypted private key
  +openssl genrsa -aes256 -out privkey.pem 2048
  +
  +# Generate public key from previously created private key.
  +openssl rsa -pubout -in privkey.pem -out pubkey.pem
  +----
  +
  +
  +Using Digital Signature Keys for signing
  +++++++++++++++++++++++++++++++++++++++++
  +
  +Now, having generated a key pair, you can sign your messages with the
  +previously mentioned Digital Signature algorithms.
  +
  +[source, clojure]
  +----
  +(require '[buddy.sign.generic :refer [sign unsign]])
  +
  +;; Import namespace for managing/reading keys
  +(require '[buddy.core.keys :as keys])
  +
  +;; Create keys instances
  +(def ec-privkey (keys/private-key "ecprivkey.pem"))
  +(def ec-pubkey (keys/public-key "ecpubkey.pem"))
  +
  +;; Use them like plain secret password with hmac algorithms for sign
  +(def signed-data (sign "mystring" ec-privkey {:alg :ec256}))
  +
  +;; And unsign
  +(def unsigned-data (unsign signed-data ec-pubkey {:alg :ec256}))
  +----
  +
  +Json Web Signature/Token
  +~~~~~~~~~~~~~~~~~~~~~~~~
  +
  +~*New in version:* 0.2~
  +
  +JSON Web Signature (JWS) represents content secured with digital
  +signatures or Message Authentication Codes (MACs) using JavaScript
  +Object Notation (JSON) based data structures.
  +
  +List of rfcs related to this feature:
  +
  +- http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-20
  +- http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-26
  +- http://tools.ietf.org/html/draft-ietf-jose-json-web-signature-26
  +
  +
  +.Supported Algorithms
  +[options="header"]
  +|=====================================================================================
  +|Algorithm name     | Hash algorithms   | Keywords           | Priv/Pub Key?
  +|Elliptic Curve DSA | sha256, sha512    | `:es256`, `:es512` | Yes
  +|RSASSA PSS         | sha256, sha512    | `:ps256`, `:ps512` | Yes
  +|RSASSA PKCS1 v1_5  | sha256, sha512    | `:rs256`, `:rs256` | Yes
  +|HMAC               | sha256*, sha512   | `:hs256`, `:hs256` | No
  +|=====================================================================================
  +
  +NOTE: almost all specified algorithms in jws-algorithms rfc are implemented. Add
  +support for missing algorithms is very easy to add possibly them will be added in
  +the near future (pull-requests welcome).
  +
  +
  +Signing data
  +^^^^^^^^^^^^
  +
  +Due to the nature of storing format, the input is restricted mainly to json objects
  +on the current version.
  +
  +.Example sign data using JWS
  +[source, clojure]
  +----
  +(require '[buddy.sign.jws :as jws])
  +
  +;; Sign data using default `:hs256` algorithm that does not
  +;; requres special priv/pub key.
  +(def data (jws/sign {:userid 1} "secret"))
  +
  +;; data should contain string similar to:
  +;; "eyJ0eXAiOiJKV1MiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyaWQiOjF9.zjenOuIAEG-..."
  +
  +(jws/unsign data "secret")
  +;; => {:userid 1}
  +----
  +
  +
  +Password Hashers
  +~~~~~~~~~~~~~~~~
  +
  +Another important part of a good authentication/authorization library
  +is providing some facilities for generating secure passwords.
  +
  +_buddy_ comes with a few functions for generating and verifying
  +passwords such as the widely used password derivation algorithms:
  +bcrypt and pbkdf2.
  +
  +.Supported password hashers algorithms
  +[options="header"]
  +|=====================================================================================
  +| Hash algorithm name  | Namespace              | Observations
  +| Bcrypt               | `byddy.hashers.bcrypt` | Recommended
  +| Pbkdf2               | `buddy.hashers.pbkdf2` | Recommended
  +| Scrypt               | `buddy.hashers.scrypt` | Recommended
  +| sha256               | `buddy.hashers.sha256` | Not recommended
  +| md5                  | `buddy.hashers.md5`    | Broken! Not Recommended
  +|=====================================================================================
  +
  +
  +The hashers  consist in two functions: `make-password` and `check-password`.
  +
  +The purpose of these functions is obvious: creating a new password,
  +and verifying incoming plain text password with previously created
  +hash.
  +
  +.Example of creating and verifying a new hash
  +[source,clojure]
  +----
  +(require '[buddy.hashers.bcrypt :as hs])
  +
  +(def myhash (hs/make-password "secretpassword"))
  +(def ok (hs/check-password "secretpassword" myhash))
  +
  +;; ok var reference should contain true
  +----
  +
  +[NOTE]
  +====
  +`make-password` accepts distinct parameters depending on hasher implementation and all functions
  +work with strings instead of bytes (unlike cryptographic hash functions).
  +====
  +
  +
  +Authentication Middleware for Ring/Compojure
  +--------------------------------------------
  +
  +Additionally, buddy commes with web library support for authentication
  +and authorization. It mainly works with ring (and compojure, since it
  +is ring-based) but in the future it can be extended for work with
  +other libraries.
  +
  +
  +Authentication
  +~~~~~~~~~~~~~~
  +
  +Buddy differs with other libraries because it takes very different approach for handling
  +authentication. In first step, it clearly split authentication and authorization in two
  +separated steps and in second step, implements it using "backends" and protocols for easy
  +extensibility.
  +
  +If you are not happy with builtin backends, you can implement your own and use it with
  +buddy middlewares without any problem.
  +
  +Authentication in buddy, has two phases:
  +
  +- Parse: parsing incoming request headers, parameters etc...
  +- Authenticate: having parsed data do authentication process, such as call auth function,
  +  unsign self contained token, etc...
  +
  +.Here is a list of built-in authentication backends:
  +[options="header"]
  +|=====================================================================================
  +| Backend name | Namespace                       | Observations
  +| Http Basic   | `buddy.auth.backends.httpbasic` |
  +| Session      | `buddy.auth.backends.session`   | Can be combined with password hashers.
  +| Token        | `buddy.auth.backends.token`     | Can be combined with password hashers and high level signing library for generate tokens.
  +| SignedToken  | `buddy.auth.backends.token`     | Based on the high level signing framework.
  +|=====================================================================================
  +
  +
  +HTTP Basic
  +^^^^^^^^^^
  +
  +The HTTP Basic authentication backend is one of the simplest and most insecure authentication
  +systems, but is a good first step for understand how buddy authentication works.
  +
  +.Simple ring handler/view for example purpose.
  +[source,clojure]
  +----
  +(require '[buddy.auth :refer (authenticated?)])
  +(require '[ring.util.response :refer (response)])
  +
  +;; Simple ring handler. This can also be a compojure router handler
  +;; or anything else compatible with ring middlewares.
  +(defn handler
  +  [request]
  +  (if (authenticated? request)
  +    (response (format "Hello %s" (:identity request)))
  +    (response "Hello Anonymous")))
  +----
  +
  +.Create an instance of authentication backend.
  +[source, clojure]
  +----
  +(require '[buddy.auth.backends.httpbasic :refer [http-basic-backend]])
  +
  +;; Http Basic backend in this case requires one function with parameter
  +;; that takes a responsability to identify the incoming request.
  +
  +;; The required function is caled in authentication of parsed data
  +;; and it receives the current ring request and parsed data from parse
  +;; phase of authentication.
  +;;
  +;; This function should return a non-nil value that
  +;; is automatically stored on :identity key on request
  +;; If it returns nil, a request is considered unauthenticated.
  +
  +(defn my-authfn
  +  [request, authdata]
  +  (let [username (:username authdata)
  +        password (:password authdata)]
  +    username))
  +
  +(def backend (http-basic-backend :realm "MyApi" :authfn my-authfn))
  +----
  +
  +
  +Now having simple view function and backend defined, you should wrap it
  +in a standard ring middleware way with buddy's authentication middleware.
  +
  +.Declare auth function and create ring app with wrapped handler.
  +[source,clojure]
  +----
  +(require '[buddy.auth.middleware :refer [wrap-authentication]])
  +
  +;; Define the main handler with *app* name wrapping it
  +;; with authentication middleware using an instance of
  +;; just created http-basic backend.
  +
  +;; Define app var with handler wrapped with buddy's authentication
  +;; middleware using just previously defined backend.
  +
  +(def app (wrap-authentication handler backend))
  +----
  +
  +Now, all incoming request with basic auth header are properly parsed and
  +request with `:identity` forwarded to real handler or next middleware.
  +
  +
  +Session
  +^^^^^^^
  +
  +The session backend has the simplest implementation because it relies
  +entirely on ring session support.
  +
  +It checks the `:identity` key on session to authenticate the user with its
  +value. The value is identified as logged user if it contains any logical true
  +value.
  +
  +See xref:examples[examples section] for complete examples for this backend.
  +
  +
  +Token
  +^^^^^
  +
  +
  +Standard
  +++++++++
  +
  +This backend works much like the basic auth backend with the difference that this works with
  +tokens that can be unpredictable.
  +
  +It parses a token and passes it to auth-fn for authentication.
  +
  +
  +Signed/Stateless
  +++++++++++++++++
  +
  +This backend is very similar to standard token backend previously explained, but instead
  +of relying on auth-fn for identify a token, it uses stateless tokens (contains all needed
  +data in a token, without storing any information about token on database as ex...).
  +
  +This backend relies on the security of the high level signing
  +framework for user authentication.
  +
  +Reference: http://lucumr.pocoo.org/2013/11/17/my-favorite-database/
  +
  +
  +Authorization
  +~~~~~~~~~~~~~
  +
  +_buddy_ also comes with an authorization system.
  +
  +The authorization system is split into two parts:
  +
  +- access rules system, using rules and logical combinators that applies to specific urls (matching
  +  them using regular expressions) or specific handlers wrapping with the `restricted` decorator.
  +- generic authorization system using exceptions for fast return and unauthorized-handler function
  +  for handle unauthorized requsts.
  +
  +
  +Access Rules System
  +^^^^^^^^^^^^^^^^^^^
  +
  +Introduction
  +++++++++++++
  +
  +The access rules are another part of the authorization system, and consist of a list of rules
  +for one or more uri's using regular expressions. One rule consists of a regular expression with its
  +associated handler (function) with authorization logic.
  +
  +.Simple rule definition example.
  +[source,clojure]
  +----
  +{:pattern #"^/admin/.*"
  + :handler admin-access}
  +----
  +
  +Function with authorization logic has the following appearance:
  +
  +[source, clojure]
  +----
  +(require '[buddy.auth :refer (authenticated?)])
  +
  +(defn should-be-authenticated
  +  [request]
  +  (authenticated? request))
  +
  +(defn should-be-safe
  +  [request]
  +  (let [method (:method request)]
  +    (if (or (= method :get) (= method :head))
  +      true
  +      false)))
  +----
  +
  +It should return a boolean value with true when request is authorized and false
  +for unauthorized.
  +
  +Also, you can combine multiple rules using logical operators in an other rule:
  +
  +[source,clojure]
  +----
  +{:pattern #"^/admin/.*"
  + :handler {:or [should-be-authenticated
  +                should-be-safe]}}
  +----
  +
  +You can nesting rules combinators as you want:
  +
  +[source,clojure]
  +----
  +{:pattern #"^/admin/.*"
  + :handler {:or [should-be-admin
  +                {:and [should-be-safe
  +                       should-be-authenticated]}]}}
  +----
  +
  +
  +Usage
  ++++++
  +
  +Now, knowing how rules can be defined, the question is, How can we use
  +it for access control for routes?
  +
  +In this case you have two ways:
  +
  +- Define a separated vector of handlers and pass it to authorization middleware
  +- Use more granular `restricted` decorator/middleware for specific functions.
  +
  +
  +For wrap separated defined access rules, you should use `wrap-access-rules`
  +buddy middleware. Here some examples of how to setup authorization for you ring
  +app:
  +
  +.Define a list of rules
  +[source,clojure]
  +----
  +;; Rules handlers used on this example are omited for code clarity
  +;; and them repsents a authorization logic for its name.
  +
  +(def rules [{:pattern #"^/admin/.*"
  +             :handler {:or [admin-access operator-access]}}
  +            {:pattern #"^/login$"
  +             :handler any-access}
  +            {:pattern #"^/.*"
  +             :handler authenticated-access}])
  +----
  +
  +.Define default behavior for not authorized requests
  +[source,clojure]
  +----
  +;; This functions works like default ring compatible handler
  +;; and should implement the default behavior for request
  +;; that are not authorized by any defined rule
  +
  +(defn reject-handler
  +  [request]
  +  {:status 403
  +   :headers {}
  +   :body "Not authorized"})
  +----
  +
  +.Wrap your handler with access rules (and run with jetty as example)
  +[source,clojure]
  +----
  +(defn -main
  +  [& args]
  +  (let [options {:rules rules :reject-handler reject-handler}
  +        app     (wrap-access-rules your-app-handler options)]
  +    (run-jetty app {:port 9090}))
  +----
  +
  +NOTE: An unauthorized exception is raised if no reject handler is
  +specified. These exceptions can be captured by generic authorization
  +middleware.
  +
  +NOTE: If request uri not match any regular expression, the default policy enter in
  +action. Default policy in buddy is *allow* but you can change the default behavior
  +specifiec `:reject` value to `:policy` option.
  +
  +
  +If you don't want a external rules list and simple want apply some rules to specific
  +ring views/handlers, your can use `restrict` decorator/middleware:
  +
  +
  +.Simple example using compojure routes.
  +[source, clojure]
  +----
  +(require '[buddy.auth.accessrules :refer [restrict]])
  +
  +(defn home-controller
  +  [request]
  +  {:body "Hello World" :status 200})
  +
  +
  +(defroutes app
  +  (GET "/" [] (restrict home-controller {:rule should-be-authenticated
  +                                         :reject-handler reject-handler}))
  +----
  +
  +
  +Generic authorization
  +^^^^^^^^^^^^^^^^^^^^^
  +
  +An other way to handle not authorized exceptions is using exceptions. It is less functional
  +but in some sircumstances can work very well.
  +
  +But how it works? It is very simple, the authorization backend wraps everything in
  +a try/catch block watching only specific exception, and in case of unauthorized exception
  +is intercepted, executes a specific function for handle it or reraise the exception.
  +
  +With this approach you can define your own middlewared/decorators with custom authorization
  +logic with fast skip raising not authorized exception using `throw-unauthorized` function.
  +
  +[source, clojure]
  +----
  +(require '[buddy.auth :refer [authenticated? throw-unauthorized]])
  +(require '[ring.util.response :refer (response redirect)])
  +
  +(defn home-controller
  +  [request]
  +  (when (not (authenticated? request))
  +    (throw-unauthorized {:message "Not authorized"}))
  +  (response "Hello World"))
  +----
  +
  +Like authentication system, authorization is also implemented using protocols. Taking advantage of
  +it, all built-in authentication backends also implements this authorization protocol (`IAuthorization`):
  +
  +[NOTE]
  +====
  +Some authentication backends require specific behavior in the authorization layer (like http-basic
  +which should return `WWW-Authenticate` header when request is unauthorized). By default, all backends
  +come with an specific implementation.
  +
  +You can overwrite the default behavior by passing your own exception handler through the
  +`:unauthorized-handler` keyword parameter in the backend constructor.
  +====
  +
  +Below is a complete example setting up a basic/generic authorization
  +system for your ring compatible web application:
  +
  +.Define the final handler
  +[source,clojure]
  +----
  +(require '[buddy.auth.backends.httpbasic :refer [http-basic-backend]])
  +(require '[buddy.auth.middleware :refer [wrap-authentication wrap-authorization]])
  +
  +;; Define the final handler wrapping it on authentication and
  +;; authorization handler using the same backend and overwriting
  +;; the default unathorized request behavior with own, previously
  +;; defined function
  +
  +(def app
  +  (let [backend (http-basic-backend
  +                 {:realm "API"
  +                  :authfn my-auth-fn
  +                  :unauthorized-handler my-unauthorized-handler})]
  +    (-> handler
  +        (wrap-authentication backend)
  +        (wrap-authorization backend))))
  +----
  +
  +NOTE: If you want know how it really works, see xref:how-it-works[How it works] section or
  +take a look on examples.
  +
  +
  +Cryptographic Api
  +-----------------
   
   Buddy has a low-level interface and a high-level interface.
   
  
positive.code: buddy documentation
  ===================
  Andrey Antukh, <niwi@niwi.be>
  0.2.0b1, 2014-06-06
  
  :toc:
  :numbered:
  
negative.code: The best documentation for this part is the source code.
  
  
  
  
  Advanced Usage
  