introspection

package
v2.11.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 7, 2021 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package introspection provide auth strategy to authenticate, incoming HTTP requests using the oauth2 token introspection endpoint, as defined in RFC 7662. This authentication strategy makes it easy to introduce apps, into a oauth2 authorization framework to be used by resource servers or other internal servers.

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/Sosivio/libcache"

	"github.com/Sosivio/go-guardian/v2/auth/strategies/oauth2/introspection"
	_ "github.com/Sosivio/libcache/lru"
)

func main() {
	srv := AuthrizationServer()
	opt := introspection.SetHTTPClient(srv.Client())
	strategy := introspection.New(srv.URL, libcache.LRU.New(0), opt)
	r, _ := http.NewRequest("GET", "/protected/resource", nil)
	r.Header.Set("Authorization", "Bearer <oauth2-token>")
	info, err := strategy.Authenticate(r.Context(), r)
	fmt.Println(info.GetUserName(), err)
}

func AuthrizationServer() *httptest.Server {
	h := func(w http.ResponseWriter, r *http.Request) {
		const body = `
		{
			"active": true,
			"client_id": "l238j323ds-23ij4",
			"username": "jdoe",
			"scope": "read write dolphin",
			"sub": "Z5O3upPC88QrAjx00dis",
			"aud": "https://protected.example.net/resource",
			"iss": "https://server.example.com/",
			"iat": 1419350238,
			"extension_field": "twenty-seven"
		}
		`
		w.WriteHeader(200)
		w.Write([]byte(body))
	}
	return httptest.NewServer(http.HandlerFunc(h))
}
Output:

jdoe <nil>
Example (Scope)
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/Sosivio/libcache"

	"github.com/Sosivio/go-guardian/v2/auth/strategies/oauth2/introspection"
	"github.com/Sosivio/go-guardian/v2/auth/strategies/token"
	_ "github.com/Sosivio/libcache/lru"
)

func main() {
	opt := token.SetScopes(token.NewScope("dolphin", "/dolphin", "GET|POST|PUT"))
	srv := AuthrizationServer()
	strategy := introspection.New(srv.URL, libcache.LRU.New(0), opt)
	r, _ := http.NewRequest("DELETE", "/dolphin", nil)
	r.Header.Set("Authorization", "Bearer <oauth2-token>")
	_, err := strategy.Authenticate(r.Context(), r)
	fmt.Println(err)

}

func AuthrizationServer() *httptest.Server {
	h := func(w http.ResponseWriter, r *http.Request) {
		const body = `
		{
			"active": true,
			"client_id": "l238j323ds-23ij4",
			"username": "jdoe",
			"scope": "read write dolphin",
			"sub": "Z5O3upPC88QrAjx00dis",
			"aud": "https://protected.example.net/resource",
			"iss": "https://server.example.com/",
			"iat": 1419350238,
			"extension_field": "twenty-seven"
		}
		`
		w.WriteHeader(200)
		w.Write([]byte(body))
	}
	return httptest.NewServer(http.HandlerFunc(h))
}
Output:

strategies/token: The access token scopes do not grant access to the requested resource

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func GetAuthenticateFunc

func GetAuthenticateFunc(addr string, opts ...auth.Option) token.AuthenticateFunc

GetAuthenticateFunc return function to authenticate request using oauth2 token introspection endpoint. The returned function typically used with the token strategy.

func New

func New(addr string, c auth.Cache, opts ...auth.Option) auth.Strategy

New return strategy authenticate request using oauth2 token introspection endpoint.

New is similar to:

fn := introspection.GetAuthenticateFunc(addr, opts...)
token.New(fn, cache, opts...)

func SetAuthorizationToken

func SetAuthorizationToken(token string) auth.Option

SetAuthorizationToken sets the introspection request's Authorization header to use HTTP Bearer Authentication with the provided token.

func SetBasicAuth

func SetBasicAuth(clientid, clinetsecret string) auth.Option

SetBasicAuth sets the introspection request's Authorization header to use HTTP Basic Authentication with the provided clientid and clientsecret.

func SetClaimResolver

func SetClaimResolver(c oauth2.ClaimsResolver) auth.Option

SetClaimResolver sets the introspection strategy ClaimResolver to resolve the authorization claim response. Default: introspection.Claim

Example
package main

import (
	"errors"
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/Sosivio/libcache"

	"github.com/Sosivio/go-guardian/v2/auth"
	"github.com/Sosivio/go-guardian/v2/auth/claims"
	"github.com/Sosivio/go-guardian/v2/auth/strategies/oauth2"
	"github.com/Sosivio/go-guardian/v2/auth/strategies/oauth2/introspection"
	_ "github.com/Sosivio/libcache/lru"
)

type ExampleClaims struct {
	ExtensionField string `json:"extension_field"`
	*introspection.Claims
}

func (c ExampleClaims) New() oauth2.ClaimsResolver {
	claim := introspection.Claims{}.New().(*introspection.Claims)
	return &ExampleClaims{Claims: claim}
}

func (c ExampleClaims) Resolve() auth.Info {
	return c
}

func (c ExampleClaims) Verify(opts claims.VerifyOptions) error {
	if v, ok := opts.Extra["extension_field"]; ok {
		str, ok := v.(string)
		if !ok {
			panic("Expected VerifyOptions.extension_field of type string")
		}
		if str != c.ExtensionField {
			return errors.New("ExampleClaim: Invalid ExtensionField")
		}
	}
	return c.Standard.Verify(opts)
}

func main() {
	srv := AuthrizationServer()
	opt := introspection.SetClaimResolver(new(ExampleClaims))
	strategy := introspection.New(srv.URL, libcache.LRU.New(0), opt)
	r, _ := http.NewRequest("GEt", "/protected/resource", nil)
	r.Header.Set("Authorization", "Bearer <oauth2-token>")
	info, err := strategy.Authenticate(r.Context(), r)
	fmt.Println(info.(ExampleClaims).ExtensionField, err)
}

func AuthrizationServer() *httptest.Server {
	h := func(w http.ResponseWriter, r *http.Request) {
		const body = `
		{
			"active": true,
			"client_id": "l238j323ds-23ij4",
			"username": "jdoe",
			"scope": "read write dolphin",
			"sub": "Z5O3upPC88QrAjx00dis",
			"aud": "https://protected.example.net/resource",
			"iss": "https://server.example.com/",
			"iat": 1419350238,
			"extension_field": "twenty-seven"
		}
		`
		w.WriteHeader(200)
		w.Write([]byte(body))
	}
	return httptest.NewServer(http.HandlerFunc(h))
}
Output:

twenty-seven <nil>

func SetClientTransport

func SetClientTransport(rt http.RoundTripper) auth.Option

SetClientTransport sets underlying http client transport.

func SetErrorResolver

func SetErrorResolver(e oauth2.ErrorResolver) auth.Option

SetErrorResolver sets the introspection strategy ErrorResolver to resolve the authorization error response. Default: oauth2.ResponseError

func SetHTTPClient

func SetHTTPClient(c *http.Client) auth.Option

SetHTTPClient sets underlying http client.

func SetTLSConfig

func SetTLSConfig(tls *tls.Config) auth.Option

SetTLSConfig ssets underlying http client tls.

func SetVerifyOptions

func SetVerifyOptions(opts claims.VerifyOptions) auth.Option

SetVerifyOptions sets the introspection strategy to verify authorization response.

Example
package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"

	"github.com/Sosivio/libcache"

	"github.com/Sosivio/go-guardian/v2/auth/claims"
	"github.com/Sosivio/go-guardian/v2/auth/strategies/oauth2/introspection"
	_ "github.com/Sosivio/libcache/lru"
)

func main() {
	srv := AuthrizationServer()
	client := introspection.SetHTTPClient(srv.Client())
	vopts := introspection.SetVerifyOptions(
		claims.VerifyOptions{
			Issuer: "https://server.example.org",
		})
	strategy := introspection.New(srv.URL, libcache.LRU.New(0), client, vopts)
	r, _ := http.NewRequest("GEt", "/protected/resource", nil)
	r.Header.Set("Authorization", "Bearer <oauth2-token>")
	info, err := strategy.Authenticate(r.Context(), r)
	fmt.Println(info, err)
}

func AuthrizationServer() *httptest.Server {
	h := func(w http.ResponseWriter, r *http.Request) {
		const body = `
		{
			"active": true,
			"client_id": "l238j323ds-23ij4",
			"username": "jdoe",
			"scope": "read write dolphin",
			"sub": "Z5O3upPC88QrAjx00dis",
			"aud": "https://protected.example.net/resource",
			"iss": "https://server.example.com/",
			"iat": 1419350238,
			"extension_field": "twenty-seven"
		}
		`
		w.WriteHeader(200)
		w.Write([]byte(body))
	}
	return httptest.NewServer(http.HandlerFunc(h))
}
Output:

<nil> strategies/oauth2/introspection: claims: standard claims issuer name does not match the expected issuer

Types

type Claims

type Claims struct {
	Active    bool   `json:"active"`
	ClientID  string `json:"client_id"`
	UserName  string `json:"username"`
	TokenType string `json:"token_type"`
	auth.Info
	*claims.Standard
}

Claims represents introspection response as defined in RFC 7662. Claims implements auth.Info and oauth2.ClaimsResolver.

func (Claims) GetExpiresAt

func (c Claims) GetExpiresAt() time.Time

GetExpiresAt return's c.ExpiresAt.

func (Claims) GetID

func (c Claims) GetID() string

GetID return's c.Info.GetID if exist, Otherwise, it return c.Subject.

func (Claims) GetScope

func (c Claims) GetScope() []string

GetScope return's c.Scope splited by space or comma.

func (Claims) GetUserName

func (c Claims) GetUserName() string

GetUserName return's c.Info.GetUserName if exist, Otherwise, it return c.UserName or c.Subject.

func (Claims) New

func (c Claims) New() oauth2.ClaimsResolver

New return's a new Claims as oauth2.ClaimsResolver.

func (Claims) Resolve

func (c Claims) Resolve() auth.Info

Resolve return's c as auth.Info.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL