Giter Site home page Giter Site logo

go-http-auth's People

Contributors

abbot avatar alecthomas avatar bbigras avatar cambraca avatar darkk avatar dependabot[bot] avatar eclipseo avatar ezeeyahoo avatar lbenguigui avatar stapelberg avatar vania-pooh 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  avatar  avatar  avatar

go-http-auth's Issues

README Example could use improvement

Hi,
This library is something I want to use, but there are no examples for how to use it. Specifically, your README does not show how to implement a Secret() func.. the comment says that the password is "hello", but it returns some hash. How should I generate that hash?
Thanks,
Rob

Cannot write custom response data in RequireAuth()

The response data is hard code as "401 Unauthorized" in RequireAuth(), is there a way to write custom response data?

Could you add a function like below?

func (a *DigestAuth) CustomRequireAuth(w http.ResponseWriter, r *http.Request, data []byte) {
    if len(a.clients) > a.ClientCacheSize+a.ClientCacheTolerance {
        a.Purge(a.ClientCacheTolerance * 2)
    }
    nonce := RandomKey()
    a.clients[nonce] = &digest_client{nc: 0, last_seen: time.Now().UnixNano()}
    w.Header().Set("WWW-Authenticate",
        fmt.Sprintf(`Digest realm="%s", nonce="%s", opaque="%s", algorithm="MD5", qop="auth"`,
            a.Realm, nonce, a.Opaque))
    w.WriteHeader(401)
    w.Write(data)
}

Documentation on how to set passwords.

This library is great, and seems to be a full replacement for the standard Apache http auth. However it is impossible to actually use if someone doesn't know how to set passwords. I think people are left doing what I am doing: scratching my head and reading the source code, guessing, and failing repeatedly.

Ultimately this needs a simple extension to the README that:

  • enumerates the ways that a password can be set
  • shows one example of using each

Ideally one example shows how to just make it read a standard .htaccess file and have it just work. Everything else is a corner case.

If I figure this out, I'll make a PR.

Digest auth should implement stale=True

From https://www.ietf.org/rfc/rfc2617.txt

The Authorization header may be included
preemptively; doing so improves server efficiency and avoids extra
round trips for authentication challenges. The server may choose to
accept the old Authorization header information, even though the
nonce value included might not be fresh. Alternatively, the server
may return a 401 response with a new nonce value, causing the client
to retry the request; by specifying stale=TRUE with this response,
the server tells the client to retry with the new nonce, but without
prompting for a new username and password.

Currently CheckAuth just returns if it doesn't find the nonce in its cache. Would be nice to support stale=TRUE.

I will send a PR

MD5Crypt takes up high CPU

[Scene]
hi all

we use the go-http-auth for request authrization, but it takes up high CPU usage, the CPU graph as follows:
image

[Code analysis]
According to the code, we see there is 1000 times loop for computing "final", we want to know if the operation is in line with expectations.

The questions are as follows:

  1. Can we delete the loop ?
  2. If you want to save the mechanism, Whether to consider the parameters(1000 times loop) can be configured?
    image

Thanks a lot !

How to dynamically enable/disable authentication?

The situation is following:

  • config.yaml is structured in the following way:
auth:
  - /path1:
      - username1: <username>
        password1: <password>
      - username2: <username>
        password2: <password>
  - /path2:
      - username: <username>
        password: <password>

Now during the app initialization, I would like to enable Basic authentication for the path if respective path record is present and disable it otherwise (i.e. let all incoming request pass). I didn't manage to do that in any way, because auth expects auth.AuthenticatedHandlerFunc while http expects http.HandlerFunc and they are not interchangeable. That means that you need 2 handler functions - one for normal http, the other for Basic auth. That is kinda cumbersome.

So I just wanted to ask if I didn't oversee something. Am I right that it cannot be done easily as the interface is design right now?

Perhaps there could be another version of auth.Wrap that would simply put an empty Username into the AuthenticatedRequest passed into the handler and would not even attempt to authenticate the request?

Let me know what you think about it, I could even write it myself and send a pull request!

What is the best way to auth using an external source like LDAP?

I would like to use go-http-auth to authenticate users with a LDAP server.

I'm able to do it with the following code but I would like to avoid having to copy code from go-http-auth (code between lines comments).

package main

import (
    "encoding/base64"
    "fmt"
    "net/http"
    "strings"

    "github.com/abbot/go-http-auth"
)

type myBasicAuth struct {
    base auth.BasicAuth
}

func (a *myBasicAuth) CheckAuth(r *http.Request) string {
    // --------------------------------------
    s := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
    if len(s) != 2 || s[0] != "Basic" {
        return ""
    }

    b, err := base64.StdEncoding.DecodeString(s[1])
    if err != nil {
        return ""
    }
    pair := strings.SplitN(string(b), ":", 2)
    if len(pair) != 2 {
        return ""
    }
    user, password := pair[0], pair[1]
    // --------------------------------------

    fmt.Printf("user: %s, password: %s\n", user, password)

    // ** ldap code here **

    return ""
}

func (a *myBasicAuth) Wrap(wrapped auth.AuthenticatedHandlerFunc) http.HandlerFunc {
    // --------------------------------------
    return func(w http.ResponseWriter, r *http.Request) {
        if username := a.CheckAuth(r); username == "" {
            a.base.RequireAuth(w, r)
        } else {
            ar := &auth.AuthenticatedRequest{Request: *r, Username: username}
            wrapped(w, ar)
        }
    }
    // --------------------------------------
}

func handle(w http.ResponseWriter, r *auth.AuthenticatedRequest) {
    fmt.Fprintf(w, "<html><body><h1>Hello, %s!</h1></body></html>", r.Username)
}

func main() {
    authenticator := &myBasicAuth{auth.BasicAuth{Realm: "example.com"}}
    http.HandleFunc("/", authenticator.Wrap(handle))
    http.ListenAndServe("127.0.0.1:8080", nil)
}

go-http-auth digest example only works with the hash included.

I realize that the hash being returned on line 22 in digest.go is simply the md5 of "john:example.com:hello". So I tried creating a new hash with "bruda:example.com:hello" , changed "john" to "bruda" on line 20, and replaced the hash on line 22. But now the authentication fails & continues to ask for login info. I double checked the original hash with the same md5 tool and it matched up with "john:example.com:hello" as expected. What am I missing here?

bcrypt support

Would you be able to add support for bcrypt, as this is now available from htpasswd?

Imlement http.Handler interface

It good that we may set basic auth on per-endpoint level

http.HandleFunc("/user/", authenticator.Wrap(handleUser))
http.HandleFunc("/book/", authenticator.Wrap(handleBook))

But for most cases it would be better to have some global "interceptor" for all endpoints.
And looks like the most simple way is to make a delegating Handler and use it with SericeMux.
Here I created a basic sample:
https://gist.github.com/stokito/24b3e6efb3e1e9357c7d964a7df2c18c

Can you add such AuthHandler into the library?

How do I generate a secret? (doco request)

The code for basic authentication says that for user "john" and password "hello" the secret is "$1$dlPL2MqE$oQmn16q49SqdmhenQuNgs1". How is this 'secret' generated? Is there a command line utilty to do this?

Authenticated Request

Hi there,

I'm running into a problem because using the library essentially changes the signature of the handle func and requires AuthenticatedRequest everywhere. This makes all subsequent method calls to methods that require http.Request fail.

DigestAuthParams does not correctly handle URI with embedded commas

URIs such as "css?family=Source+Sans+Pro:400,700,4" are not parsed correctly due to the embedded commas. In this case, result["uri"] ends up being "/css?family=Source+Sans+Pro:400", subsequently the digest computed in CheckAuth does not match the response in the Proxy-Authorization header.

GET http://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro HTTP/1.1^M
Host: fonts.googleapis.com^M
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:43.0) Gecko/20100101 Firefox/43.0^M
Accept: text/css,/;q=0.1^M
Accept-Language: en-US,en;q=0.5^M
Accept-Encoding: gzip, deflate^M
Referer: http://elm-lang.org/assets/style.css^M
Proxy-Authorization: Digest username="test", realm="", nonce="FRPnGdb8lvM1UHhi", uri="/css?family=Source+Sans+Pro:400,700,400italic,700italic|Source+Code+Pro", algorithm=MD5, response="fdcdd78e5b306ffed343d0ec3967f2e5", opaque="lEgVjogmIar2fg/t", qop=auth, nc=00000001, cnonce="e76b05db27a3b323"^M
Connection: keep-alive^M

A quick Google indicates this is a common issue in digest code, see
https://bz.apache.org/bugzilla/show_bug.cgi?id=37132
rails/rails#5485
https://twistedmatrix.com/trac/ticket/6445

I will send a PR to fix

intermittent failure to find passwords (possible race?)

I'm finding this works great on most of my sites, and has been a drop-in replacement for Apache, but I have some exceptions. On a page that embeds two iframes that hit my protected (ie hits the server to check passwords in parallel twice at nearly the same moment), even if I have the password cached already, it fails to find a password, and gets int a loop where no matter how many times I enter it, it fails.

Curious if there is a race condition behind this. I'm attempting to debug.

Go 1.10: misc_test.go:35: Fatalf format %s reads arg #3, but call has only 2 args

b6a92f4 does not pass unit tests with Go 1.10. At least:

+ GOPATH=/builddir/build/BUILD/go-http-auth-b6a92f468f2b01961e796d20e3ec5bbb8a8297d6/_build:/usr/share/gocode
+ go test -buildmode pie -compiler gc -ldflags '-extldflags '\''-Wl,-z,relro  '\'''
# github.com/abbot/go-http-auth
./misc_test.go:35: Fatalf format %s reads arg #3, but call has only 2 args
FAIL    github.com/abbot/go-http-auth [build failed]

New release

Hey hey,

a bit of time passed by since the last release was made. Please add a new one since master branch contains a few important bug fixes. The latest release 0.3.0 isn't working for me, master is. :)

Thanks in advance and 👋 from Germany!

htpasswd utility support

I've created htpasswd files using the htpasswd utility and, while go-http-auth supports the file format, the hashed passwords aren't matching up.

This isn't my area of expertise, but I suspect go-http-auth is using a different salt than htpasswd and perhaps there are some other minor differences in how the MD5 and SHA algorithms are used between htpasswd and go-http-auth. Or I am I missing something?

If htpasswd encrypted passwords aren't going to be supported by go-http-auth, how about a similar utility that will create an httpasswd file that will work with go-http-auth.

Very happy with the package, by the way.

Thanks.

concurrent map read and map write

With around 100 parallel clients there is a crash observed. Similar to what was reported in #62

Stack trace -

fatal error: concurrent map read and map write

goroutine 16622 [running]:
runtime.throw(0xb0c9fd, 0x21)
/usr/local/go/src/runtime/panic.go:774 +0x72 fp=0xc0005ad7f0 sp=0xc0005ad7c0 pc=0x42f5d2
runtime.mapaccess2_faststr(0xa1ef60, 0xc0002a20c0, 0xc000275a28, 0x10, 0xc0006e0098, 0x0)
/usr/local/go/src/runtime/map_faststr.go:116 +0x48f fp=0xc0005ad860 sp=0xc0005ad7f0 pc=0x4144ff
github.com/abbot/go-http-auth.(*DigestAuth).CheckAuth(0xc000252120, 0xc0005d8100, 0x0, 0x0, 0x0)
/root/go/src/edmservice/pkg/mod/github.com/abbot/[email protected]/digest.go:185 +0x847 fp=0xc0005adaf8 sp=0xc0005ad860 pc=0x9822a7
github.com/abbot/go-http-auth.(*DigestAuth).Wrap.func1(0xbe0420, 0xc00028c000, 0xc0005d8100)
/root/go/src/edmservice/pkg/mod/github.com/abbot/[email protected]/digest.go:219 +0x57 fp=0xc0005adb90 sp=0xc0005adaf8 pc=0x9841a7
net/http.HandlerFunc.ServeHTTP(0xc000254060, 0xbe0420, 0xc00028c000, 0xc0005d8100)
/usr/local/go/src/net/http/server.go:2007 +0x44 fp=0xc0005adbb8 sp=0xc0005adb90 pc=0x7cf504
net/http.(*ServeMux).ServeHTTP(0x1050020, 0xbe0420, 0xc00028c000, 0xc0005d8100)
/usr/local/go/src/net/http/server.go:2387 +0x1bd fp=0xc0005adc18 sp=0xc0005adbb8 pc=0x7d13dd
net/http.serverHandler.ServeHTTP(0xc0002ca000, 0xbe0420, 0xc00028c000, 0xc0005d8100)
/usr/local/go/src/net/http/server.go:2802 +0xa4 fp=0xc0005adc48 sp=0xc0005adc18 pc=0x7d2954
net/http.(*conn).serve(0xc000520140, 0xbe1a20, 0xc00075a940)
/usr/local/go/src/net/http/server.go:1890 +0x875 fp=0xc0005adfc8 sp=0xc0005adc48 pc=0x7ce2f5
runtime.goexit()
/usr/local/go/src/runtime/asm_amd64.s:1357 +0x1 fp=0xc0005adfd0 sp=0xc0005adfc8 pc=0x45bb91
created by net/http.(*Server).Serve
/usr/local/go/src/net/http/server.go:2927 +0x38e

Example in README missing "auth"

import (
        "github.com/abbot/go-http-auth"

...should be...

import (
        auth "github.com/abbot/go-http-auth"

i.e. Add "auth" and the example becomes a working example.

Double lock in digest

Hello. I have ran into a problem where in digest.go#L262 da.Purge is called while da.mutex is locked, with da.Purge itself trying to acquire lock on it.

This causes double lock and all further digest authentication requests hang until they time out.

This can be fixed either by removing lines 74, 75, 92 and 99, so that da.Purge is always called when da.mutex is locked but is not trying to acquire lock itself, or by adding da.mutex.Unlock() and da.mutex.Lock() around line 262 so that da.Purge is only called when da.mutex is not locked.

please tag and release

Please consider to assign version numbers and tag releases.
Tags/releases are useful for downstream package maintainers (in Debian and other distributions) to export source tarballs, automatically track new releases and to declare dependencies between packages.
Read more in the Debian Upstream Guide.

Thank you.

please tag and release

Hey,

a bit of time passed by since the last release was made. Please add a new one since master branch contains a few important bug fixes. The latest release 0.4.0 isn't working for me, master is. :)

use of raw map for digest.clients leads to concurrent writes to map

At some point a mutex was added to mediate access to digest.clients but it was removed in subsequent commits for some reason. Rather than relying on correct use of a mutex, why not use a sync.Map?

When a server instance is hit with a sufficient number of concurrent requests (client code below) concurrent write to digest.clients results in a panic.

package main

import (
	"fmt"
	"net/http"
	"sync"
	"time"

	"github.com/bobziuchkovski/digest"
)

func main() {
	wg := sync.WaitGroup{}
	wg.Add(80)

	startTime := time.Now()
	for i := 0; i < 80; i++ {
		go func() {
			defer wg.Done()
			t := digest.NewTransport("admin", "admin")
			req, err := http.NewRequest("GET", "http://127.0.0.1", nil)
			if err != nil {
				fmt.Println(err)
				return
			}
			_, err = t.RoundTrip(req)
			if err != nil {
				fmt.Println(err)
				return
			}
		}()
	}

	wg.Wait()
	fmt.Printf("time taken: %v", time.Now().Sub(startTime).String())
}

DigestAuth functions aren't thread-safe (Race conditions)

go build -race, will add instrumentation to catch race conditions.
It caught problem within DigestAuth.clients (map)

I'm attaching a copy of digest.go.
I changed the mutex to be a read/write mutex, so you could have finer grain control over it.
this copy doesn't cause problems with -race

Also I started to fix golint problems https://github.com/golang/lint. But stopped, because it was getting out of hand. (Sorry for dirtying up the answer)
digest.txt

Thanks for your awesome work on the repo!!

digest.txt is really digest.go!

Update example?

As the methodes like NewBasicAuthenticator etc. are deprecated, is there an updated of example of how to use this package?

algorithm

digest.go

algorithm=MD5 , not algorithm="MD5"

Allow use inside proxy server

Proxy authentication is nearly identical to origin server authentication except for a few details like header names. Would be nice if this lib could be used in a proxy server implementation. I'm working on this and will submit a PR.

Plugable backend for digest_client struct

Hi,

I'm evaluating this lib to use it in our proyect. However, we have a distributed environment and we can't share these values across the nodes. Maybe a plugable backend like postgres would be a nice idea. What do you think?

PD: Thanks for your great work

digest CheckAuth assumes nonce-count always increases

The digest module CheckAuth function makes the reasonable assumption that the client-sent nonce-count ("nc") always increases. Unfortunately, in practice, because a client can have multiple connections to a server, some possibly through proxies and/or via AJAX, client-sent nonce-counts don't always increase from the POV of the server. Strictly the requirement is that a nonce-count is not reused, not that it always increases. I am observing this as I try to use go-http-auth in a real world setting. I will send a PR to either track nonces with a bitmap or add an option to turn off nc checking. Thank you for open sourcing this excellent lib.
References:
https://lists.w3.org/Archives/Public/ietf-http-wg/2003JulSep/0006.html
https://code.google.com/p/chromium/issues/detail?id=37526

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.