Giter Club home page Giter Club logo

go-guardian's Introduction

GoDoc Go Report Card Coverage Status CircleCI

❗ Cache package has been moved to libcache repository

Go-Guardian

Go-Guardian is a golang library that provides a simple, clean, and idiomatic way to create powerful modern API and web authentication.

Overview

Go-Guardian sole purpose is to authenticate requests, which it does through an extensible set of authentication methods known as strategies.
Go-Guardian does not mount routes or assume any particular database schema, which maximizes flexibility and allows decisions to be made by the developer.
The API is simple: you provide go-guardian a request to authenticate, and go-guardian invoke strategies to authenticate end-user request.
Strategies provide callbacks for controlling what occurs when authentication should succeeds or fails.

Installing

Using go-guardian is easy. First, use go get to install the latest version of the library.

go get github.com/shaj13/go-guardian/v2

Next, include go-guardian in your application:

import "github.com/shaj13/go-guardian/v2"

Why Go-Guardian?

When building a modern application, you don't want to implement authentication module from scratch;
you want to focus on building awesome software. go-guardian is here to help with that.

Here are a few bullet point reasons you might like to try it out:

  • provides simple, clean, and idiomatic API.
  • provides top trends and traditional authentication methods.
  • provides two-factor authentication and one-time password as defined in RFC-4226 and RFC-6238
  • provides a mechanism to customize strategies, even enables writing a custom strategy

Strategies

JWT, Opaque, and oauth2 packages provide early access to advanced or experimental functionality to get community feedback. Their APIs and functionality may be subject to breaking changes in future releases.

Examples

Examples are available on GoDoc or Examples Folder.

Documentation

API docs are available on GoDoc.

Contributing

  1. Fork it
  2. Download your fork to your PC (git clone https://github.com/your_username/go-guardian && cd go-guardian)
  3. Create your feature branch (git checkout -b my-new-feature)
  4. Make changes and add them (git add .)
  5. Commit your changes (git commit -m 'Add some feature')
  6. Push to the branch (git push origin my-new-feature)
  7. Create new pull request

License

Go-Guardian is released under the MIT license. See LICENSE

go-guardian's People

Contributors

briwagner avatar choffah avatar hmgowda avatar m87carlson avatar shaj13 avatar stensonb 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

go-guardian's Issues

Fix for CVE-2024-28180 (Improper Handling of Highly Compressed Data ) introduced through gopkg.in/square/go-jose.v2

What version of Go are you using (go version)?

$ go version v1.22

Does this issue reproduce with the latest release?

Yes

What version of Go-Guardian are you using ?

Go-Guardian Version:  github.com/shaj13/go-guardian/v2 v2.11.5

What did you do?

Github security scan (dependabot) and checkmarx has reported a CVE in this library that is introduced through gopkg.in/square/go-jose.v2 v2.5.1.

CVE information can be found here : GHSA-c5q2-7r4c-mv6g
The version of go-jose library need to updated. The path with the fix is available in github.com/go-jose/go-jose/v4 4.0.1 onwards.

What did you expect to see?

No Vulnerabilities.

What did you see instead?

Saw CVE-2024-28180 GHSA-c5q2-7r4c-mv6g

jwt Example doens't return a token

What version of Go are you using (go version)?

1.13

Does this issue reproduce with the latest release?

yes

What version of Go-Guardian are you using?

latest

What did you do?

https://play.golang.org/p/NlbR34g1GRM
I just ran the jwt example

What did you expect to see?

I expect to get a token in the response

What did you see instead?

token:  
➜  ~ curl  -k http://127.0.0.1:8080/v1/book/1449311601 -u admin:admin
Author: Ryan Boyd 
➜  ~ curl  -k http://127.0.0.1:8080/v1/auth/token -u admin:admin
token:  
➜  ~ 

Token is empty

Authenticate username, password passed from frontend

Hi, I would like to ask how to use authenticator to verify username/pass instead of request

Here is the authenticator from the go guardian package

       return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	log.Println("Executing Auth Middleware")
	for k, v := range r.URL.Query() {
		log.Printf("%s: %s\n", k, v)
	}
	user, err := authenticator.Authenticate(r)

What I want to do is to check the user by cheking the username/password passed from frontend form
Like

         func SetupGoGuardian(u, p string) (*authentication.User, error) {
                   // u here is username from form
                   // p here is password from form
               log.Printf("User username %s", u)
               cfg := &ldap.Config{
	            Port:         "389",
	            Host:         "ldapadmin.test",
	            BindDN:       "cn=admin,dc=ldapadmin,dc=test",
	            BindPassword: "root",
	            BaseDN:       "dc=ldapadmin, dc=test",
	            Filter:       "(uid=%s)",
               }
              authenticator = auth.New()
              cache = store.NewFIFO(context.Background(), time.Minute*10)
              strategy := ldap.NewCached(cfg, cache)
              authenticator.EnableStrategy(ldap.StrategyKey, strategy)
                  user, err := authenticator.Authenticate(u, p) // this what I want to check my username password,
	      if err != nil {
                      return &authentication.User{}, nil
                  }
                   return (///////////////////you are now allowed)

Any ideas ?

Password included in token from jwt strategy example

What version of Go are you using (go version)?

$ go version
1.16

Does this issue reproduce with the latest release?

Yes

What version of Go-Guardian are you using ?

Go-Guardian Version: 
v2.11.2

What did you do?

Run the jwt token example in the repo with basic login.

What did you expect to see?

A token without password.

What did you see instead?

The password included in plain text in the payload of the token:

{
  "Extensions": {
    "x-go-guardian-basic-password": [
      "admin"
    ]
  },
  "Groups": null,
  "ID": "1",
  "Name": "admin",
  "aud": [
    ""
  ],
  "exp": 1615318474,
  "iat": 1615318174,
  "nbf": 1615318174,
  "sub": "1"
}

Rotated secrets always triggers a new secret to be generated

What version of Go are you using (go version)?

$ go version
1.16

Does this issue reproduce with the latest release?

Yes

What version of Go-Guardian are you using ?

Go-Guardian Version: 
v2.11.3

What did you do?

Trying to get rotated secrets working and have been looking at https://play.golang.org/p/5N-5fWa0mfN (posted by @shaj13) for some help. This is also found somewhere in the examples but can't find it right now.

The issue is that jwt.SecretsKeeper's methods Get and KID doesn't use pointers in it's signature definitions so changes to r.LastRotation in KID is not saved to the keeper struct.

For example this func (r RotatedSecrets) KID() string should be this func (r *RotatedSecrets) KID() string?

What did you expect to see?

That time.Now().After(r.LastRotation) would be false if within specified rotation duration.

What did you see instead?

That time.Now().After(r.LastRotation) is always true as r.LastRotation is always 0.

Unable to use TLS with LDAP strategy for authentication

LDAP Result Code 200 "Network Error": ldap: already encrypted

This error is from the line https://github.com/go-ldap/ldap/blob/c9551dc8a15abc270d5ea1a59366622cba6c09a5/conn.go#L292

I am getting an error when the underlying LDAP package is trying to call StartTLS.
If I switch the port from 636 to 389 & remove the TLS Config, authentication is successful but in plain text.

        cfg := &ldap.Config{
                BaseDN: "ou=Users,dc=mandalorian,dc=net",
                Port: "636",
                Host: "openldap.example.com",
                Filter: "(uid=%s)",
                TLS: &tls.Config{
                     MaxVersion:         tls.VersionTLS12,
                    InsecureSkipVerify: true},
        }
        ...
        strategy = ldap.NewCached(cfg, cacheObj)

        r, _ := http.NewRequest("GET", "/", nil)
        r.SetBasicAuth("cara", "dune")

        info, err := strategy.Authenticate(r.Context(), r)

How do I authenticate to my openldap with TLS ? Note that I can make it work in python.

Issue with example directory

What version of Go are you using (go version)?

$ go version
go version go1.18.3 linux/amd64

Does this issue reproduce with the latest release?

Yes

What version of Go-Guardian are you using ?

Go-Guardian Version:  v2.11.5
Libcache Version: v1.0.5

What did you do?

Hello,
I just want to follow the jwt example https://github.com/shaj13/go-guardian/blob/master/_examples/jwt/main.go
But the function RegisterOnExpired was deprecated and no-longer works.
Can you update the example directory on this repo.

What did you expect to see?

The program init and run

What did you see instead?

$> go run ./...
panic: RegisterOnExpired no longer available

goroutine 1 [running]:
github.com/shaj13/libcache/internal.(*Cache).RegisterOnExpired(0x18?, 0x7c80a0?)
	/home/xxx/go/pkg/mod/github.com/shaj13/[email protected]/internal/cache.go:379 +0x27
github.com/shaj13/libcache.(*cache).RegisterOnExpired(0xc00009e120, 0x6?)
	/home/xxx/go/pkg/mod/github.com/shaj13/[email protected]/cache.go:245 +0x56
main.setupGoGuardianJWT()
	/home/xxx/go/src/gitlab.com/xxx/my-project/cmd/go-guardian-jwt.go:33 +0x17d
main.main()
	/home/xxx/go/src/gitlab.com/xxx/my-project/cmd/main.go:20 +0x1d
exit status 2

Doesn't work with LDAP version >3.4.4

What version of Go are you using (go version)?

$ go version
go version go1.22.4 linux/amd64

Does this issue reproduce with the latest release?

yes

What version of Go-Guardian are you using ?

Go-Guardian Version: 
github.com/shaj13/go-guardian/v2 v2.11.5

What did you do?

var strategy auth.Strategy
var cacheObj libcache.Cache

func InitLDAPConnection(cfg *config.Config) {
	ldapConfig := &ldap.Config{
		BaseDN:       cfg.LDAPBaseDN,
		BindDN:       "uid=" + cfg.LDAPBindUser + "," + cfg.LDAPBaseDN,
		Port:         cfg.LDAPPort,
		Host:         cfg.LDAPHost,
		BindPassword: cfg.LDAPBindPassord,
		Filter:       "(uid=%s)",
	}
	cacheObj = libcache.FIFO.New(0)
	cacheObj.SetTTL(time.Minute * 10)
	strategy = ldap.NewCached(ldapConfig, cacheObj)
}

What did you see instead?

# github.com/shaj13/go-guardian/v2/auth/strategies/ldap
/home/user/go/pkg/mod/github.com/shaj13/go-guardian/[email protected]/auth/strategies/ldap/ldap.go:71:9: cannot use ldap.DialURL(cfg.URL, opts...) (value of type *"github.com/go-ldap/ldap/v3".Conn) as conn value in return statement: *"github.com/go-ldap/ldap/v3".Conn does not implement conn (wrong type for method Close)
                have Close() (error)
                want Close()

Works ok with LDAP version 3.4.4:

github.com/go-ldap/ldap/v3 v3.4.4

Feature: Access token, Refresh token, OAuth2

Hi,

I am currently using the jwt strategy for development process.
This works good so far, however, I can see there is some caveats:

  • lifespan must be huge or user experience will be bad (have to relog each x minutes)
  • jwt could be intercepted by a malicious third party and this jwt will be usage for probably a long time (lifespan config value)

I think creating a new strategy like refreshTokenStrategy will resolve these issues.

There is a full specification of the OAuth2 here: https://datatracker.ietf.org/doc/html/rfc6749

Protocol Flow: https://datatracker.ietf.org/doc/html/rfc6749#section-1.2

What is a refresh token: https://datatracker.ietf.org/doc/html/rfc6749#section-1.5
What is an access token: https://datatracker.ietf.org/doc/html/rfc6749#section-1.4

Authorization code grant: https://datatracker.ietf.org/doc/html/rfc6749#section-4.1
Resource owner Password credentials grant: https://datatracker.ietf.org/doc/html/rfc6749#section-4.3 (case we want to auth a microservice for example)

I could keep linking all the docs, but I think this isn't necessary as someone made a great OAuth server implementation here: https://github.com/go-oauth2/oauth2

My point is: could we create an oauth strategy based on the OAuth server implementation that go-oauth2 made?

How to setup jwt strategy properly

Main

func main() {
	setupGoGuardian()
	http.Handle("/ping", controllers.Ping())
	http.Handle("/login", middlewares.Auth(http.HandlerFunc(controllers.CreateToken())))
	fmt.Println("starting to listen on port " + config.Port)
	http.ListenAndServe(":"+config.Port, nil)
}

SetupGoGuardian

func setupGoGuardian() {
	rs := middlewares.RotatedSecrets{
		Secrets: make(map[string][]byte),
	}
	cache := libcache.LRU.New(0)
	cache.SetTTL(time.Minute * 5)
	cache.RegisterOnExpired(func(key, _ interface{}) {
		cache.Peek(key)
	})
	basicStrategy := basic.NewCached(users.ValidateUser, cache)
	jwtStrategy := jwt.New(cache, rs)
	middlewares.Strategy = union.New(jwtStrategy, basicStrategy)
}

Auth Middleware

func Auth(next http.Handler) http.HandlerFunc {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// log.Println("Executing Auth Middleware")
		_, user, errList := Strategy.AuthenticateRequest(r)

		if errList != nil {
			code := http.StatusUnauthorized
			for _, err := range errList.(union.MultiError) {
				switch err.(type) {
				case *InternalError:
					code = http.StatusInternalServerError
				}
			}
			http.Error(w, http.StatusText(code), code)
			return
		}
		log.Printf("User %s Authenticated\n", user.GetUserName())
		r = auth.RequestWithUser(user, r)
		next.ServeHTTP(w, r)
	})
}

Controller CreateToken

func CreateToken() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		switch r.Method {
		case http.MethodPost:
			u := auth.User(r)
//What should I do here? how can I add the jwt to the RotatedSecrets 
// And how can I add extra fields to the token for example permissions, so the token will include permissions: "kill","example"
			token, err := jwt.IssueAccessToken(u, ??)
                        if err != nil { 
                                //something
                        }
			body := fmt.Sprintf("token: %s \n", token)
			w.Write([]byte(body))
		default:
			http.Error(w, "method is not allowed", http.StatusMethodNotAllowed)
			return
		}
	}
}

And what should I do with the rotatedSecret struct


type RotatedSecrets struct {
	Secrets          map[string][]byte
	LatestID         string
	RotationDuration time.Duration
	LastRotation     time.Time
	
}

func (r RotatedSecrets) KID() string {
	if time.Now().After(r.LastRotation) {
		r.LastRotation = time.Now().Add(r.RotationDuration)
		r.LatestID = "your generated id"
		r.Secrets[r.LatestID] = []byte("your generated secrets") <<<<<where should I get the generated secrets?
	}
	return r.LatestID
}

func (r RotatedSecrets) Get(kid string) (key interface{}, alg string, err error) {
	s, ok := r.Secrets[kid]
	if ok {
		return s, jwt.HS256, nil
	}
	return nil, "", fmt.Errorf("Invalid KID %s", kid)
}

JWT refresh token

I have managed to get a simple login working from my Ember app that i'm building but have a couple of questions.
I don't find any support for refresh tokens in the jwt strategy. Are there any plans to add support?
Also, maybe token expiration time should be configurable?

Great work on this project! 👌

Edit:
Realized you actually can configure token expiration time with SetExpDuration.

How to actively logout/invalidate a user?

Sorry if this is not the right place to ask, but I wonder how I can log off a user when he hits an endpoint like /auth/logoff? I'm using the basic + jwt strategy from the example. So the user logs in using his credentials, then receives his token that he then uses for all further requests (including timed keep-alive requests to renew the token before expiration).

The client can simply delete the token and "feel" logged off, sure, but then the server would still accept it until it is expired, right? How can you invalidate a token, do I have to delete the entries from the cache by hand? Or can I use auth.Revoke() somehow like below?

func logoutHandler(w http.ResponseWriter, r *http.Request) {
	u := auth.User(r)
	err := auth.Revoke(strategy, u)
	if err != nil {
		log.Println("Error revoking user: ", err)
	}
	body := "success"
	w.Write([]byte(body))
}

kubernetes token review strategy

Context:
The Kubernetes auth strategy can be used to authenticate incoming HTTP requests using a Kubernetes Service Account Token. This method of authentication makes it easy to introduce apps into a Kubernetes Pod.

Use Case:
the go-guardian user creates Kubernetes service account for review the token, the Kubernetes auth strategy uses the token review service account to query Kubernetes token review API to validate the incoming HTTP request token.
This allows apps to authenticate other pods in same cluster (M2M) and users in the Kubernetes cluster.

Example:

$ cat << EOF > token.yaml 
apiVersion: v1
kind: ServiceAccount
metadata:
  name: token-reviewer
  namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: role-tokenreview-binding
  namespace: token-demo
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:auth-delegator
subjects:
- kind: ServiceAccount
  name: token-reviewer
  namespace: default 
EOF

$ kubectl apply -f token.yaml
$ kubectl describe secret  tokenreview-token-k46tm
$ curl -k -X "POST" "https://127.0.0.1:8443/apis/authentication.k8s.io/v1/tokenreviews" \
     -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IkJmV2s3QjYzeTZkeWROYmhuZDVSdWx6bkVEekZOMFpfUDJyQ3hldElGdUUifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6InRva2VuLXJldmlld2VyLXRva2VuLWxoa21wIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6InRva2VuLXJldmlld2VyIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiODQ2ODM3YTEtYjcyZC00YTFkLWJhM2ItOTJmM2Y5OTUxYTM4Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6dG9rZW4tcmV2aWV3ZXIifQ.WvfQwfviCZ3wDQalZlJliFfvsrkcUcdn5U93tp9NsjnQWJ0ZsYuafoSmsKhI6qPqKWo_gw4_a9yYm3saYnfdIAmhwA_m37OJ0w6KDyanvY51vB6tvEVEYn6Ee4XWbql1dom2W_QZOvYqVYyn0_v1ophpFBDifffrCFnS6bVihQX3YJJwBHjkDHYyKK7_tcdcoQeNfXemHeqA9Ss6TQaOcUDJS2S311Z8en9uwDuxviTcBVZyTTvAsL2UNG3x2HCVW5yR0yIgvJoRduaMvdFlPYXed06xu40aVifgXGwR50T1cBs6P0Dzqm2C4ousSukng4mplz4qSd7_xpYXyV-dBA' \
     -H 'Content-Type: application/json; charset=utf-8' \
     -d $'{
  "kind": "TokenReview",
  "apiVersion": "authentication.k8s.io/v1",
  "spec": {
    "token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IkJmV2s3QjYzeTZkeWROYmhuZDVSdWx6bkVEekZOMFpfUDJyQ3hldElGdUUifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6InRva2VucmV2aWV3LXRva2VuLWs0NnRtIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6InRva2VucmV2aWV3Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiNzQ3ZGY1NWYtYmU3Mi00OGU3LWJkYTItMzhjZTY4YWQ4NDE0Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6dG9rZW5yZXZpZXcifQ.Ta8L251BD2zajjYlc77NoacJrPo4yrdTHp_50ncbtNHAfk72DFaOIGJ2c6BD1DXkv_akLQJgD95x57N5uZlls3gXmOAjwfQkby2WjKzsJPMJyvTIPZuvduWDc9WGvin82uKIdlY8F-598uGGnykTG0t2xy6fb6WHnqafWPJqhoqIWh7qafPGnT29lMqrHZxIM4hXOFMTjM1wzWPcu2J4olM2e4W3zFgrbFyqYLBiC95nnYuTU8gIgpQnf038uP1Pbl_VGeWJypFZ0wa98bc5kNGOsOnKIyK6X1vQ8taT2h_5VFbHKPGrgTmoICwd_MPkps8vs7e-h065LhjcGb8ZZg"	
	}
}'

{
  "kind": "TokenReview",
  "apiVersion": "authentication.k8s.io/v1",
  "metadata": {
    "creationTimestamp": null,
    "managedFields": [
      {
        "manager": "curl",
        "operation": "Update",
        "apiVersion": "authentication.k8s.io/v1",
        "time": "2020-08-14T17:51:48Z",
        "fieldsType": "FieldsV1",
        "fieldsV1": {"f:spec":{"f:token":{}}}
      }
    ]
  },
  "spec": {
    "token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IkJmV2s3QjYzeTZkeWROYmhuZDVSdWx6bkVEekZOMFpfUDJyQ3hldElGdUUifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6InRva2VucmV2aWV3LXRva2VuLWs0NnRtIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6InRva2VucmV2aWV3Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiNzQ3ZGY1NWYtYmU3Mi00OGU3LWJkYTItMzhjZTY4YWQ4NDE0Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6dG9rZW5yZXZpZXcifQ.Ta8L251BD2zajjYlc77NoacJrPo4yrdTHp_50ncbtNHAfk72DFaOIGJ2c6BD1DXkv_akLQJgD95x57N5uZlls3gXmOAjwfQkby2WjKzsJPMJyvTIPZuvduWDc9WGvin82uKIdlY8F-598uGGnykTG0t2xy6fb6WHnqafWPJqhoqIWh7qafPGnT29lMqrHZxIM4hXOFMTjM1wzWPcu2J4olM2e4W3zFgrbFyqYLBiC95nnYuTU8gIgpQnf038uP1Pbl_VGeWJypFZ0wa98bc5kNGOsOnKIyK6X1vQ8taT2h_5VFbHKPGrgTmoICwd_MPkps8vs7e-h065LhjcGb8ZZg"
  },
  "status": {
    "authenticated": true,
    "user": {
      "username": "system:serviceaccount:default:tokenreview",
      "uid": "747df55f-be72-48e7-bda2-38ce68ad8414",
      "groups": [
        "system:serviceaccounts",
        "system:serviceaccounts:default",
        "system:authenticated"
      ]
    }
  }
}

API:
https://docs.openshift.com/online/pro/rest_api/apis-authentication.k8s.io/v1.TokenReview.html

Feature: ldap strategy collect user group

Context:
LDAP strategy does not fetch user groups and only fill the user info and the rest of the data mapped to extensions.

Tasks:

  • update LDAP strategy to fetch user groups
  • Test changes

Feature: implement opaque token revocation

What version of Go are you using (go version)?

$ go version

Does this issue reproduce with the latest release?

What version of Go-Guardian are you using ?

Go-Guardian Version: 

What did you do?

What did you expect to see?

What did you see instead?

Issue with go-guardian jwt example

https://github.com/shaj13/go-guardian/blob/master/_examples/jwt/main.go example here contains come code with deprecated RegisterOnExpired method:

func setupGoGuardian() {
	keeper = jwt.StaticSecret{
		ID:        "secret-id",
		Secret:    []byte("secret"),
		Algorithm: jwt.HS256,
	}
	cache := libcache.FIFO.New(0)
	cache.SetTTL(time.Minute * 5)
	cache.RegisterOnExpired(func(key, _ interface{}) {
		cache.Peek(key)
	})
	basicStrategy := basic.NewCached(validateUser, cache)
	jwtStrategy := jwt.New(cache, keeper)
	strategy = union.New(jwtStrategy, basicStrategy)
}

Causes panic: RegisterOnExpired no longer available

auth/strategies/digest/header_test.go failed periodically

Error:

    header_test.go:186: 
        	Error Trace:	header_test.go:186
        	Error:      	Not equal: 
        	            	expected: "Digest username=test, nc=00000001"
        	            	actual  : "Digest nc=00000001, username=test"
        	            	
        	            	Diff:
        	            	--- Expected
        	            	+++ Actual
        	            	@@ -1 +1 @@
        	            	-Digest username=test, nc=00000001
        	            	+Digest nc=00000001, username=test
        	Test:       	TestString

Link:
https://github.com/shaj13/go-guardian/blob/master/auth/strategies/digest/header_test.go#L181

Suggested Solution:

  • use contains instead of equal

otp package must verify totp also in the past timestamps

Context:
TOTP verify failed due network latency and transmission delay
as defined in https://tools.ietf.org/html/rfc6238#section-5.2 , The validation system should compare OTPs not only with
the receiving timestamp but also the past timestamps that are within
the transmission delay

need to add a new field to struct e.g DelayWindow , and the verify method check if the type is totp so its generated 3 code for past, current, feature timestamp and validate the user code against three generated codes.

e.g

counters := []uint64{interval()}
if TOTP {
for i := 1; i <= DelayWindow; i++ {
counters = append(counters, counters[0]-i)
counters = append(counters, counters[0]+i)
}
and verify()

LDAPS Schema does not work with 389 + Start TLS Server

What version of Go are you using (go version)?

$ go version 1.17

Does this issue reproduce with the latest release?

yes

What version of Go-Guardian are you using ?

Go-Guardian Version: 2.11.4

What did you do?

I configured ldap against a server that has port 636 "ldaps" disabled, and only uses StartTLS on port 389.

What did you expect to see?

I expected to connect and authenticate with ldap credentials

What did you see instead?

"Network Error": read tcp x.x.x.x:60677->x.x.x.x:389: read: connection reset by peer

I believe this should still be scheme ldap, and ldaps should be used against an LDAP server with SSL enabled on port 636.

This would remediate the issue:

diff --git a/auth/strategies/ldap/ldap.go b/auth/strategies/ldap/ldap.go
index ec9b920..cc00906 100644
--- a/auth/strategies/ldap/ldap.go
+++ b/auth/strategies/ldap/ldap.go
@@ -56,10 +56,13 @@ func dial(cfg *Config) (conn, error) {
 	opts := []ldap.DialOpt{}
 
 	if cfg.TLS != nil {
-		scheme = "ldaps"
 		opts = append(opts, ldap.DialWithTLSConfig(cfg.TLS))
 	}
 
+  if cfg.Port == "636" {
+    scheme = "ldaps"
+  }
+
 	addr := fmt.Sprintf("%s://%s:%s", scheme, cfg.Host, cfg.Port)
 	return ldap.DialURL(addr, opts...)
 }

Union strategy: missing log for basic when authentication fails

Scenario: Using Union strategy (basic+token)

When basic fails, and token fails too, the log shows "strategies/token: Invalid token" for the token, but only "Invalid credentials" for basic without the strategy name.

strategies/union: [strategies/token: Invalid token, Invalid credentials]

fix x509 test failure

What version of Go are you using (go version)?

locally 1.17
ci/cd 1.13.1

Does this issue reproduce with the latest release?

yes

What version of Go-Guardian are you using ?

Go-Guardian Version: latest 

What did you do?

Run test local and on ci/cd

What did you expect to see?

x509 test pass

What did you see instead?

--- FAIL: TestStrategyAuthenticate (0.00s)
--- FAIL: TestStrategyAuthenticate/valid_client_certificate (0.00s)
x509_test.go:94: valid client certificate: Got unexpected error: x509: certificate has expired or is not yet valid
--- PASS: TestStrategyAuthenticate/expired_client_certificate (0.00s)

feature request: redis as a cache

What version of Go-Guardian are you using ?

Go-Guardian Version: 2.11.4

It would be nice to be able to use redis as a cache for the store instead of in-memory.
This would allow more flexibility for scaling to multiple instances and help with app upgrades.

ldap over TLS : Result Code 200 "Network Error": ldap: already encrypted

What version of Go are you using (go version)?

$ go version : go1.15.8

Does this issue reproduce with the latest release?

YES

What version of Go-Guardian are you using ?

Go-Guardian Version: v2.9.0

What did you do?

Here is the content of our setupGoGuardian

func setupGoGuardian() {

rootCA, err := x509.SystemCertPool()
if err != nil {
	log.Printf("Failed to load system cert:%v", err)
	// return nil, err
}
if rootCA == nil {
	log.Printf("root ca is nil")
	rootCA = x509.NewCertPool()
}

certs, _ := ioutil.ReadDir("ad_certs")
for _, cert := range certs {
	if !cert.IsDir() {
		ldapCert, err := ioutil.ReadFile(fmt.Sprintf("ad_certs/%s", cert.Name()))
		if err != nil {
			log.Printf("Failed to read ad cert:%v", err)
			continue
		}
		ok := rootCA.AppendCertsFromPEM(ldapCert)
		if !ok {
			log.Printf("AD cert of %s is not addeded.", cert.Name())
			continue
		}
	}
}

cfg := &ldap.Config{
	BaseDN: "xxxxxx",
	BindDN: "xxxxxx",
	Port: "636",
	Host: "xxxxx",
	TLS: &tls.Config{
		ServerName:         "xxxx",
		RootCAs:            rootCA,},
	BindPassword: "xxxx",
	Filter:       "xxxx",
}

cacheObj = libcache.FIFO.New(0)
cacheObj.SetTTL(time.Minute * 5)
cacheObj.RegisterOnExpired(func(key, _ interface{}) {
	cacheObj.Peek(key)
})

strategy = ldap.NewCached(cfg, cacheObj)
}

and a basic sample middleware :

func middleware(next http.Handler) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	log.Println("Executing Auth Middleware")
	user, err := strategy.Authenticate(r.Context(), r)
	if err != nil {
		code := http.StatusUnauthorized
		errorstring := fmt.Sprintf("%s", err)
		http.Error(w, errorstring, code)
		log.Printf("%s", err)
		return
	}
	log.Printf("User %s Authenticated\n", user.GetUserName())
	next.ServeHTTP(w, r)
})

What did you expect to see?

the authentication should be validated. that work perfectly without TLS (clear LDAP on port 389) ... but not supported soon

What did you see instead?

we got this error message from ldap provider : LDAP Result Code 200 "Network Error": ldap: already encrypted

Could you please drive us to the solution ??
Thank you so much for your help and have a nice day.
Best regards.

Feature: support apikey strategy

Context:
currently go-guardian does not support the API keys
authentication strategy.

apikey authentication method needs to be added in order to expand go-guardian capabilities.

need design/refactor before this issue land since apikey overlaps with the bearer strategy
in order to avoid code duplication.

Digest Example doesn't work on Chrome or FF

Chrome returns "MD5" as algorithm, not "md5" and you get error

 send error strategies/digest: algorithm Does not match value in provided header 

Workaround:

alg := digest.SetHash(crypto.MD5, "MD5")
strategy = digest.New(validateUser, c, alg)

Consider changing ID() method in auth.Info interface to UserID()?

I was trying to use this library in my project and ran into a naming collision of sorts. I have a few GORM models including a base Model and a User model. Model includes a few fields that get used in all of my other models, such as ID, created at, updated at, etc. My other models then have something like this.

type User struct {
    Model

    Email string
    HashedPassword []byte
}

What seemed appropriate to do at the time was add the functions from your auth.Info interface to my User model so that I could just pass my User into functions like Append, for example, or return my User model instead of a DefaultUser instance from my validateLogin function. That part works perfectly, but it came with other compromises.

One of the functions in the auth.Info interface is ID(). One of my fields in my base Model (and by extension my User model and indeed all my models) is also ID. Obviously I can change the name of the field, and that's what I've done for now, but I either name it Id which works but causes go-lint to yell at me, or name it something like ModelID which just feels... weird. I could also not use the base Model in my User model and manually add the necessary fields from the base Model, naming the id field UserID in the process, but that creates code duplication and means if I have to add to or edit the base Model I also most likely have to edit the User model. Not too big of a deal but a bit of a code smell.

What I would like to propose is renaming the ID() method on the auth.Info interface to UserID(), as it not only avoids this issue but also makes it match better with the UserName() method. Of course if you're privy to information that I'm not on why that wouldn't work I absolutely understand, and I can work around the issue with either one of the methods I described above or writing some functions to convert my User models to DefaultUser instances, but I figured it was worth having the discussion.

Question: How to achieve digest auth that survives after service restarts.

I'm using Digest strategy and works fine until I restart my service. Chrome re-challenges user to give creds again. Strategy returns:
userInfo = nil, err = Invalid Response
to all web requests. I'm using FIFO lib cache FWIW.

Do I need to implement my own cache implementation that stores values on disk to survive restarts?

I'm trying to replace nginx reverse proxy and this doesn't happen w/nginx so this is a loss in functionality as well and user issue.

Feature: expose cache keys

Context:

currently, cache interface and FIFO does not expose the cache keys
in order to expand cache API need to expose the cache keys

Tasks:

  • add keys function to the cache interface
  • expose FIFO cache keys

token strategy/pkg docs

Tasks:

  • add docs to token strategy (godoc)
  • add links to the readme (api-key, bearer, x-header)

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.