Giter Club home page Giter Club logo

buddy-auth's People

Contributors

alexanderkiel avatar avelino avatar burhanloey avatar cryptox8 avatar delitescere avatar dijonkitchen avatar dimovich avatar eipplusone avatar ericnormand avatar jarofghosts avatar jonpither avatar krivachy avatar mike706574 avatar mping avatar niwinz avatar oliyh avatar pflingstring avatar philippkueng avatar prestancedesign avatar quan-nh avatar r0man avatar rgkirch avatar ricardojmendez avatar rundis avatar rwilson avatar slipset avatar stig avatar terop avatar tirkarthi avatar yzernik avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

buddy-auth's Issues

Regarding fn->multi macro

Hi,

Love this library.

I took a look at fn->multi macro, and I don't think just wrapping respond function around the body will make it able to handle async request.

Take wrap-authorization middleware for example. Even when you wrap respond around it, you still only pass 1 argument (request) to the handler. For Ring handler that supports both sync and async, yes it will work, but that only means that it will always choose the sync implementation. For Ring handler that only supports async, it will just throw error saying not enough arguments.

So I tried to implement some buddy middlewares for async handlers and this is how I make them work.

Also, I noticed there is no tests for async handler. There is only test for the macro.

Usage of buddy.auth.http/-get-header

Hi,
More than an actual problem is an implementation detail question/observation. According to the description, buddy-auth is:

Authentication and Authorization facilities for ring and ring based web applications

This means the request and response should meet the Ring SPEC. If you check the :headers of the Request Map, you'll find that the keys of the map, must be downcased, which lead us to get a particular value with a simple key lookup, e.g. (get-in req [:headers "authorization"])

:headers
  (Required, IPersistentMap)
  A Clojure map of downcased header name Strings to corresponding header value 
  Strings.

The current implementation of header lookup is a case-insensitve search through the map keys using buddy.auth.http/-get-header. Any thoughts on why is like this?

Adding a transformation function to jwt/jws backends.

I want to unify the data structure of how the identity data structure looks like. With basic and token authorizations, the authfn lets me hook in and choose what I want to return as an identity.

Can we also have this for all the other backends? JWT, JWS and Session?

Bad Request and 'missing-required-key' in response with JWS-backend, RSA key

Hi, I'm having a weird issue. Everything appears to be configured correctly. But when I send a request, i'm getting a 400 and the following response body.

{
  "errors": {
    "Authorization": "missing-required-key"
  }
}

I've done some debugging, and I've verified that at in buddy.auth.middleware.wrap-authentication below, authdata actually has the data that were pulled from the token at the point of the assoc call. I just can't figure out where it's becoming unhappy.

(defn wrap-authentication
  "Ring middleware that enables authentication for your ring
  handler. When multiple `backends` are given each of them gets a
  chance to authenticate the request."
  [handler & backends]
  (fn [request]
    (if-let [authdata (authenticate-request request backends)]
      (handler (assoc request :identity authdata))
      (handler request))))

I'm using a luminus +auth-jwe +swagger setup. I've commented out most of the other middle ware handlers to verify that this is the source of the problem. Here's the full setup:

(ns gs-communication-ms.middleware
  (:require [gs-communication-ms.env :refer [defaults]]
            [clojure.tools.logging :as log]
            [gs-communication-ms.layout :refer [*app-context* error-page]]
            [ring.middleware.anti-forgery :refer [wrap-anti-forgery]]
            [ring.middleware.webjars :refer [wrap-webjars]]
            [ring.middleware.format :refer [wrap-restful-format]]
            [gs-communication-ms.config :refer [env]]
            [ring.middleware.flash :refer [wrap-flash]]
            [immutant.web.middleware :refer [wrap-session]]
            [ring.middleware.defaults :refer [site-defaults wrap-defaults]]
            [buddy.auth.middleware :refer [wrap-authentication wrap-authorization]]
            [buddy.auth.accessrules :refer [restrict]]
            [buddy.auth :refer [authenticated?]]
            [buddy.auth.backends.token :refer [jwe-backend jws-backend]]
            [buddy.sign.jwt :refer [encrypt]]
            [buddy.core.nonce :refer [random-bytes]]
            [buddy.core.keys :as ks]
            [clojure.java.io :as io]
            [clj-time.core :refer [plus now minutes]])
  (:import [javax.servlet ServletContext]))

(defn wrap-context [handler]
  (fn [request]
    (binding [*app-context*
              (if-let [context (:servlet-context request)]
                ;; If we're not inside a servlet environment
                ;; (for example when using mock requests), then
                ;; .getContextPath might not exist
                (try (.getContextPath ^ServletContext context)
                     (catch IllegalArgumentException _ context))
                ;; if the context is not specified in the request
                ;; we check if one has been specified in the environment
                ;; instead
                (:app-context env))]
      (handler request))))

(defn wrap-internal-error [handler]
  (fn [req]
    (try
      (handler req)
      (catch Throwable t
        (log/error t)
        (error-page {:status 500
                     :title "Something very bad has happened!"
                     :message "We've dispatched a team of highly trained gnomes to take care of the problem."})))))

(defn wrap-csrf [handler]
  (wrap-anti-forgery
    handler
    {:error-response
     (error-page
       {:status 403
        :title "Invalid anti-forgery token"})}))

(defn wrap-formats [handler]
  (let [wrapped (wrap-restful-format
                  handler
                  {:formats [:json-kw :transit-json :transit-msgpack]})]
    (fn [request]
      ;; disable wrap-formats for websockets
      ;; since they're not compatible with this middleware
      ((if (:websocket? request) handler wrapped) request))))

(defn on-error [request response]
  (error-page
    {:status 403
     :title (str "Access to " (:uri request) " is not authorized")}))

(defn wrap-restricted [handler]
  (restrict handler {:handler authenticated?
                     :on-error on-error}))

(def secret (random-bytes 32))

;(def token-backend
;  (jwe-backend {:secret secret
;                :options {:alg :a256kw
;                          :enc :a128gcm}}))

(def token-backend
  (jws-backend {:secret (ks/public-key (io/resource "pubkey.pem"))
                :token-name "GS-Token"
                :options {:alg :rs256}}))

(defn token [username]
  (let [claims {:user (keyword username)
                :exp (plus (now) (minutes 60))}]
    (encrypt claims secret {:alg :a256kw :enc :a128gcm})))

(defn wrap-auth [handler]
  (let [backend token-backend]
    (-> handler
        (wrap-authentication backend)
        ;(wrap-authorization backend)
        )))

(defn wrap-base [handler]
  (->
    ((:middleware defaults) handler)
      wrap-auth
      ;wrap-webjars
      ;wrap-flash
      ;(wrap-session {:cookie-attrs {:http-only true}})
      ;(wrap-defaults
      ;  (-> site-defaults
      ;      (assoc-in [:security :anti-forgery] false)
      ;      (dissoc :session)))
      ;wrap-context
      ;wrap-internal-error
    ))

my token data are pretty generic

{
  "alg": "RS256",
  "typ": "JWT"
}
{
  "exp": 1487719225,
  "user_name": "user",
  "authorities": [
    "ROLE_USER",
    "ROLE_ACTUATOR"
  ],
  "jti": "4c452287-25f0-4eaa-8179-b0652583e9bf",
  "client_id": "demo",
  "scope": [
    "read",
    "write"
  ]
}

But I don't see where it's expecting a key that might be 'missing', where the middleware decides to make the request return a 400, etc

"No implementation of method: :-to-bytes of protocol:" error using jws-backend with RSA key

Hi, I'm trying use the JWS backend for a service. Like so:

(def token-backend
  (jws-backend {:secret (ks/public-key (io/resource "pubkey.pem"))
                :token-name "Token"}))

The request processing is throwing the following error:

:cause No implementation of method: :-to-bytes of protocol: #'buddy.core.codecs/IByteArray found for class: org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPublicKey
 :via
 [{:type java.lang.IllegalArgumentException
   :message No implementation of method: :-to-bytes of protocol: #'buddy.core.codecs/IByteArray found for class: org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPublicKey
   :at [clojure.core$_cache_protocol_fn invokeStatic core_deftype.clj 568]}]
 :trace
 [[clojure.core$_cache_protocol_fn invokeStatic core_deftype.clj 568]
  [clojure.core$_cache_protocol_fn invoke core_deftype.clj 560]
  [buddy.core.codecs$eval19241$fn__19242$G__19232__19247 invoke codecs.clj 60]
  [buddy.core.codecs$to_bytes invokeStatic codecs.clj 69]
  [buddy.core.codecs$to_bytes invoke codecs.clj 66]
  [buddy.core.mac$eval19698$fn__19699 invoke mac.clj 91]
  [buddy.core.mac$eval19608$fn__19609$G__19599__19616 invoke mac.clj 44]
  [buddy.core.mac$verify invokeStatic mac.clj 247]
  [buddy.core.mac$verify invoke mac.clj 240]
  [buddy.sign.jws$fn__20104 invokeStatic jws.clj 33]
  [buddy.sign.jws$fn__20104 invoke jws.clj 30]
  [buddy.sign.jws$verify_signature invokeStatic jws.clj 95]
  [buddy.sign.jws$verify_signature invoke jws.clj 87]
  [buddy.sign.jws$unsign invokeStatic jws.clj 133]
  [buddy.sign.jws$unsign invoke jws.clj 127]
  [buddy.sign.jwt$unsign invokeStatic jwt.clj 82]
  [buddy.sign.jwt$unsign invoke jwt.clj 78]
  [buddy.auth.backends.token$jws_backend$reify__20813 _authenticate token.clj 46]

I saw a reference to something similar in the buddy-sign issues (funcool/buddy-sign#34), but that was when the signing api was being used directly. I'm just setting up the backend with a public key and passing it to wrap-authentication.

NPE when using some shared secrets

I have tried to use jws_backend function and sometimes works fine but for some shared secrets does not seem to work. I wonder if has to do with the length of the shared secret or some lengths cannot be used? This is the full stacktrace when a request is made to the backend and tries to unsign the shared secret contained in the token:

java.lang.NullPointerException: null
at clojure.string$replace.invokeStatic(string.clj:101)
at clojure.string$replace.invoke(string.clj:75)
at buddy.core.codecs$safebase64__GT_bytes.invokeStatic(codecs.clj:116)
at buddy.core.codecs$safebase64__GT_bytes.invoke(codecs.clj:109)
at buddy.sign.jws$unsign.invokeStatic(jws.clj:176)
at buddy.sign.jws$unsign.invoke(jws.clj:168)
at buddy.auth.backends.token$jws_backend$reify__15853._authenticate(token.clj:53)
at buddy.auth.middleware$wrap_authentication$fn__15974$fn__15978.invoke(middleware.clj:36)
at buddy.auth.middleware$wrap_authentication$fn__15974.invoke(middleware.clj:31)
at compojure.core$routing$fn__10214.invoke(core.clj:144)

I am using version 0.9.0

Rate Limiting?

it should be handy if rate limiting is provided by buddy who also hold all account info

Broken tokens should raise an error resulting in 401, not 500

For example, I wrote a test:

(testing "authenticated access with bad credentials"
    (d/let-flow
     [r (api/handler (-> (mock/request :post "/authenticate")
                         (mock/header "Authorization" "Token xyzzy")))]
     (is (= (:status r) 401))))

However, instead I get a 500 with a weird random exception:

Error in handler-test
Uncaught exception, not in assertion.
expected: nil
  actual: com.fasterxml.jackson.core.JsonParseException: Unexpected character ('�' (code 65533 / 0xfffd)): expected a valid value (number, String, array, object, 'true', 'false' or 'null')
 at [Source: java.io.StringReader@5ccb2c27; line: 1, column: 2]

Request method in Access Rules

Hello,

I have a question/feature request. Say I have a rule defined like
this:

{:uri "/comments" :handler authenticated-user}

This would match both GET /comments and POST /comments. What
I really want is just match POST /comments. I could do this
with the following rule:

{:uri "/comments" :handler {:or [get-request authenticated-user]}}}

It feels a bit strange to have to "unmatch" a rule when I want to
match on the request method as well. I think the common case is
that you have different rules depending on the request method.

Would you be open to add something like this to a rule:

{:uri "/comments" :methods #{:post}} :handler authenticated-user}
{:uri "/comments" :methods #{:delete}} :handler authenticated-user}

This would match only ŕequests with the given request
methods. Without the :methods keyword it would match everything
as is. I think this would make writing access rules a bit easier.

What do you think?

Roman

Improve documentation about how use jwe and link to the buddy-sign documentation for detailed JWE doc.

I'm really enjoying using buddy-auth. Thanks much for this work!

I have a question about JWE (and this is probably more about JWE than buddy-auth, but hoping someone here might be able to shed some light).

The JWS and JWE examples are great, thanks for providing those.

The way I understand using JWS: 2 programs know a shared secret. One program uses shared secret to sign, and the other program uses the same secret to validate signature. If I understand that correctly, then that makes sense.

But I'm a little confused about how to take the JWE example and use it in the real world. If the program that encrypts the payload creates the nonce, then how to share that nonce with the program that needs to decrypt the payload?

Thanks for your help,
Dave

Include an admin-user function defintion in docs

In 6.2. Rules Handlers portion of the docs, an undefined function admin-user is used. It wasn't immediately clear to me how I could define such a function for my own use and an example would be very helpful.

Authorization questions

What does wrap-authorization do?

When I have this handler for an access rule:

(defn authenticated-user
  [request]
  (if (authenticated? request)
    true
    (error "Only authenticated users are allowed")))

it seems that having wrap-access-rules and wrap-authentication is enough. What is the use-case for the wrap-authorization middleware?

Why does error return a status 400 here?

I'd assume that the wrap-authorization middleware would check if authenticated? is true, and if not, return the string I supplied with error together with status code 401, and if it is true, return the string I supplied with status code 403. Am I wrong in expecting this behaviour? Because currently, using error will result in status code 400.

edit: I found out that, if I do add the wrap-authorization middleware, and have my access-rule handler return false instead of error, the status codes are as expected: 401 when not authenticated?, 403 otherwise. This is nice and all, but that means I cannot simply override the error message by using error (because then I end up with 400)

New maintaner

The README notes:

NOTE: this project is in maintencance mode, and looking for a new maintainer.

What is maintenance mode? What are the criteria for choosing a new maintainer? I may be happy to maintain the project, but know neither what qualifies someone to maintain the library nor what maintenance mode entails.

Authorization scheme for HTTP Basic Authentication should be case insensitive

Hi,

According to RFC 2617, the authorization scheme should be case insensitive; thus, Basic and basic should both be valid.

Here's the relevant part:

HTTP provides a simple challenge-response authentication mechanism
that MAY be used by a server to challenge a client request and by a
client to provide authentication information. It uses an extensible,
case-insensitive token to identify the authentication scheme...

Thanks!

Default token name for JWS should be Bearer?

Just a nitpick, but from what I have seen on other sources, the default token name for JWS usually seems to be Bearer as opposed to Token. Should that be changed? One other advantage is that it might be easier to differentiate bt. normal token-based vs jwt based requests.

Multiple backends

I would like to use multiple backends. Would you take a PR that extends wrap-authentication to work with multiple backends? Like this:

(wrap-authentication http-basic-backend jws-backend)

The idea is to try all passed backends in order. If one of them succeeds call the handler, otherwise return the failure response of the last backend?

Roman

Allow for successful authorization of requests that already contain :identity

For unit testing I've found it useful to simulate authenticated requests by simply adding an :identity entry to my test ring requests. This allows me to create tests for authorization that don't tie themselves to any particular authentication method.

However, buddy-auth doesn't allow this out of the box. The problem is that middleware/authentication-request will in effect (assoc :identity nil) to any request that doesn't match a particular authentication backend, overwriting any existing value of :identity. To get around this, I've created my own authentication backend that will retrieve this value if it already exists in the request:

(def map-entry-backend
  (reify
    buddy.auth.protocols/IAuthentication
    (-parse [_ request]
      (:identity request))
    (-authenticate [_ request data]
      data)))

Other users may find this functionality handy. It may be good to build in this functionality by either

  1. Changing middleware/authentication-request to respect any existing values of :identity
  2. Providing map-entry-backend as a build in back-end (possibly with a better name)

I guess the main issue is any security risk - I'm assuming that it is not possible for any ring handler to insert an identity entry itself, but I don't know enough about ring to say for sure. If this is an issue, then option 2 might still be worthwhile provided that the documentation adequately warns not to use it in production.

Delay the decision of which secret to use

Hello Andrey, I ran into the use case where they JWS my API receives might be signed by different public keys each time and I have to read the token's header claim kid (or jku) to figure out against which key I need to verify the signature (the :secret param of the jws backend: https://github.com/funcool/buddy-auth/blob/master/src/buddy/auth/backends/token.clj#L36). I was wondering if it's a good idea to extend the jws backend implkeyementation to receive a function as the :secret in which case the JWS header is passed to it and returns the appropriate secret.

A real example from my project:
When my web service starts I query my authentication service to receive all the public keys available to verify JWS' signatures:

(defstate keys
  "Holds the public keys used for verifying JWS' signatures"
  :start (...))

With the current implementation, when defining the middleware of my app the only choice I have is to pick one of the keys defined above:

defn base-middleware
  "Application base middlewares."
  [handler]
  (let [secret (first keys)]
    (-> handler
        ...
        (wrap-authentication (app.auth/jws-backend secret))
        ...
        )))

But what I would like is to be able to choose a key depending on the claims of the JWS itself, for example:

defn base-middleware
  "Application base middlewares."
  [handler]
  (let [secret (fn [header]
                      (get-key-by-id keys (:kid header)))]
    (-> handler
        ...
        (wrap-authentication (app.auth/jws-backend secret))
        ...
        )))

What do you think?

NullPointerException marked

java.lang.NullPointerException: null
at buddy.auth.middleware$wrap_authorization$fn__14021.invoke(middleware.clj:81) ~[classes/:na]

commit 32d3b70 "Remove slingshot usage"
Missing throw argument
81 - (throw+)))))))
83 + (throw)))))))

I guess avobe changes "(throw e)" ?

Not possible to modify content-type?

I'm using Buddy with Basic Auth and the api-defaults Ring middleware. The Unauthorized response gets a Content-Type of octet-stream. In a (Safari) browser, this results in an empty file being downloaded on Esc from the Basic Auth dialog.

I'm looking for a way to set Content-Type to say text/plain, but without having to re-create the same response as Buddy Auth. The only solution now seems to be to create a full response myself in the :on-error function.

Authenticating with Firebase token is impossible the secret changes dynamically

When trying to authenticate a user with a token generated by firebase it is not possible with this library directly.
According to the documentation (https://firebase.google.com/docs/auth/admin/verify-id-tokens#verify_id_tokens_using_a_third-party_jwt_library) the public key to verify the signature of the token has to be obtained from https://www.googleapis.com/robot/v1/metadata/x509/[email protected], which changes continuously. Furthermore, it is not an unique key, but there are many, and to choose which one, it is necessary to check one field from the header (:kid).
There is another library (alekcz/charmander) that takes care of updating those keys and using them with buddy.sign.jwt directly, but lacks the backend wrappers that buddy-auth offers.
It could be as easy as allowing the parameter secret in method jws-backend

(defn jws-backend
[{:keys [secret authfn unauthorized-handler options token-name on-error]
:or {authfn identity token-name "Token"}}]
{:pre [(ifn? authfn)]}
(reify
proto/IAuthentication
(-parse [_ request]
(parse-header request token-name))
(-authenticate [_ request data]
(try
(authfn (jwt/unsign data secret options))
(catch clojure.lang.ExceptionInfo e
(let [data (ex-data e)]
(when (fn? on-error)
(on-error request e))
nil))))
proto/IAuthorization
(-handle-unauthorized [_ request metadata]
(if unauthorized-handler
(unauthorized-handler request metadata)
(handle-unauthorized-default request)))))
to be either a function or either a literal. If it would be a function (ifn?) then it could be called with data as parameter, allowing expandability for this and maybe other cases.
The line
(authfn (jwt/unsign data secret options))
would become
(authfn (jwt/unsign data (if (ifn? secret) (secret data) secret) options))
Maintaining backwards compatibility.

buddy.auth.backends.token/handle-unauthorized-default violates RFC 7235 section 4.1. WWW-Authenticate

RFC 7235 section 4.1. WWW-Authenticate specifies:

A server generating a 401 (Unauthorized) response MUST send a WWW-Authenticate header field containing at least one challenge.

However, buddy.auth.backends.token/handle-unauthorized-default sends a 401 status response without a WWW-Authenticate header:

(defn- handle-unauthorized-default
"A default response constructor for an unauthorized request."
[request]
(if (authenticated? request)
{:status 403 :headers {} :body "Permission denied"}
{:status 401 :headers {} :body "Unauthorized"}))

Access Rules: re-matches on path-info breaks pattern matching

Discovered when trying to use buddy-auth access rules in a project with compojure route definitions that use compojure's context. I haven't tested to see whether it's specific to compojure or whether it occurs without compojure or without the use of the context fn.

The crux of the problem is the compiled :pattern matcher, specifically that it matches against :path-info if it exists, rather than always using the :uri. Here's the relevant code:

;; rwilson- Excerpt from buddy.auth.accessrules/compile-access-rule, with comments added
(fn [request]
  (let [pattern (:pattern accessrule)
        ;; rwilson- the inclusion of :path-info here breaks the ability to match the
        ;;          whole uri, which is problematic because :path-info can be non-nil
        ;;          and also irrelevant to the matching, as demonstrated below.
        uri (or (:path-info request)
                 (:uri request))]
    (when (and (matches-request-method request request-method)
               (seq (re-matches pattern uri)))
      {})))

Here's an example. Given the following:

(defroutes routes
  (context "/account/:account-id[a-zA-Z0-9_]" [account-id]
    (GET "/show" _ (account/show account-id))))

(def access-rules
  {:rules [:pattern #"^/account/.*$"
           :handler authenticated-user?]})

Say, then, that a request is made to "/account/12345/show". The problem is that the request will have a :path-info value of "/show" and a :uri value of "/account/12345/show". Since the compiled matcher uses :path-info over :uri if it exists, the above access-rule will not match. But, it doesn't make terribly much sense to put an access rule on just "/show". After all, it's every URI with "/account/" at the start that needs protecting, not URIs with "/show" at the end.

Multiple backends using multiple tokens throws NPE

Hi,

I'm trying out the multiple backends support. If you have two backends, with each being a jws-backend, then I've noticed that in the wrap-authentication function, an NPE occurs.

This is because (proto/authenticate current request rsq) is potentially called when rsq is null.

This happens because of the check inside of wrap-authentication: if (and (nil? rsq) last?). The null check only occurs if last? is true; the backend is the last one. So for the first backend, if nothing is returned from (proto/parse current request), it will still attempt to perform (proto/authenticate current request rsq) with a null rsq, which causes an NPE.

Authorization: Bearer XXX as well a Token?

It is a pretty common expectation that JWT's can be passed using the Bearer token approach. It is also recommended and the main source of info for JWT:

https://jwt.io

It is a common compliant our customers give us that they need to use Token instead of Bearer when using our API. They need to write more code to support it etc...

Would you accept pull requests to all both to be specified?

Document available options

I'm having difficulty figuring out how all the middleware and options work together.

There are three middleware: wrap-access-rules, wrap-authentication, wrap-authorization. How do these work together and which are necessary? It seems like if I use wrap-access-rules, I may omit wrap-authorization.

What options are available for backends? I see :unauthorized-handler, does a :unauthenticated-handler exist?
What options are available for wrap-access-rules? I see :rules and :on-error. Does/should :on-error handle unauthenticated requests? Unauthorized requests? When should :on-error be used instead of the :unauthorized-handler option specified in the backend?

These concerns should be better documented.

Wording, spelling, grammar

There are a lot of wording, spelling, and grammar mistakes throughout the documentation. I understand English isn't everyone's first language; I just wanted to make a note of this for future contributors.

Full examples

Hi,

I extended the example with dependencies here, should these kinds of full examples be included? I can rebase to current version. Perhaps should go into a separate repository and linked in a wiki or doc.

https://github.com/funcool/buddy-auth/tree/118fe135881ce52dfffe21d73df4fec664c987d4/examples/session

See also this implementation of token based security with buddy:

http://rundis.github.io/blog/2015/buddy_auth_part1.html

Another example:
https://adambard.com/blog/clojure-auth-with-buddy/

http-basic doc need amending

In the http-basic section it says to add (wrap-authentication), but it seems that (wrap-authorization) middleware is also needed.

Without this middleware no 'basic auth' dialog is shown to enter the username/password.

This caught me out because it didn't even occur to me that I needed to add "authorization" to do "authentication".

Thanks!

wrap-authorization ignores 'raised' unauthorized exceptions in async mode

With Ring 3-arity contract, exceptions thrown in the same thread bubble back to the middleware. However, if any non-blocking IO was to happen between wrap-authorization and throw-unauthorized, those exceptions would arrive via raise callback. One such instance could be a OAuth2 authorization backend calling the token endpoint. A simplified example:

(defn handler [request respond raise]
  (future ; simulates non-blocking IO switching threads
    (try
      (throw-unauthorized) ; simplified example
      (catch Throwable t (raise t))))) ; raise any handler exceptions per Ring spec

(-> handler
    (wrap-authorization nil) ; backend doesn't get called anyway
    (apply {:request-method :get} println println nil)) ; run it
; => #ExceptionInfo
; expected: wrap-authorization to catch the raised exception
; and handle it with the backend

Possible fix

(defn wrap-authorization
  (fn
    ; [...]
    ([request respond raise]
     (try (handler request respond
           (fn [e] (try (respond (authorization-error request e backend))
                     (catch Throwable t (raise t))))
          (catch Exception e
            (respond (authorization-error request e backend)))))))

http-basic with access rules?

I started with wrap-authorization with the httpbasic handler, which worked well as long as I peppered my controllers with authenticated? checks. If unauthenticated, I was prompted for my httpbasic credentials, and only got an "unauthorized" error if I refused to provide them.

Now I'm trying to switch to wrap-access-rules so I can protect URLs with a regex and DRY up my auth config. But now everything returns my on-error response, and I can't figure out how to prompt for httpbasic credentials when I receive an authentication failure.

Does buddy-auth include a way to this? Can the docs please get updated with an example?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.