niso

package module
v0.0.0-...-e416dba Latest Latest
Warning

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

Go to latest
Published: Apr 19, 2017 License: BSD-3-Clause Imports: 13 Imported by: 0

README

NISO

An improved Golang OAuth2 server library

Go Report Card Build Status GoDoc

Introduction

NISO is an OAuth2 server library for the Go language, forked from OSIN. The project can be used build your own OAuth2 authentication service as per the speficiation at http://tools.ietf.org/html/rfc6749.

This fork offers the following advantages over OSIN:

  • Cleaner, simpler, majorly side-effect free API
  • Improved error messages and propagated error context using pkg/errors
  • Context support
  • Improved test coverage

Example Server

server := niso.NewServer(niso.NewServerConfig(), storage.NewExampleStorage())

// Authorization code endpoint
http.HandleFunc("/authorize", func(w http.ResponseWriter, r *http.Request) {
    resp, err := server.HandleHTTPAuthorizeRequest(
        r,
        func(ar *niso.AuthorizationRequest) (bool, error) {
            return true, nil
        },
    )
    if err != nil {
        log.Printf("Error handling authorize request %v", err)
    }

    niso.WriteJSONResponse(w, resp)
})

// Access token endpoint
http.HandleFunc("/token", func(w http.ResponseWriter, r *http.Request) {
    resp, err := server.HandleHTTPAccessRequest(
        r,
        func(ar *niso.AccessRequest) (bool, error) {
            return true, nil
        },
    )
    if err != nil {
        log.Printf("Error handling access request %v", err)
    }

    niso.WriteJSONResponse(w, resp)
})

http.ListenAndServe(":14000", nil)

Example Access

Open in your web browser:

http://localhost:14000/authorize?response_type=code&client_id=1234&redirect_uri=http%3A%2F%2Flocalhost%3A14000%2Fappauth%2Fcode

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func StatusCodeForError

func StatusCodeForError(error *Error) int

StatusCodeForError returns http status code for a given error code as per (https://tools.ietf.org/html/rfc6749#section-5.2)

func WriteJSONResponse

func WriteJSONResponse(w http.ResponseWriter, r *Response) error

WriteJSONResponse encodes the Response to JSON and writes to the http.ResponseWriter

Types

type AccessData

type AccessData struct {
	// ClientData information
	ClientID string

	// Access token
	AccessToken string

	// Token expiration in seconds
	ExpiresIn int32

	// Requested scope
	Scope string

	// Redirect Uri from request
	RedirectURI string

	// Date created
	CreatedAt time.Time

	// Type of grant used to issue this token
	GrantedVia GrantType

	// Data to be passed to storage. Not used by the library.
	UserData interface{}
}

AccessData represents an access grant (tokens, expiration, client, etc)

func (*AccessData) ExpireAt

func (d *AccessData) ExpireAt() time.Time

ExpireAt returns the expiration date

func (*AccessData) IsExpiredAt

func (d *AccessData) IsExpiredAt(t time.Time) bool

IsExpiredAt returns true if access expires at time 't'

type AccessRequest

type AccessRequest struct {
	GrantType GrantType
	Code      string
	ClientID  string

	RefreshToken string

	RedirectURI   string
	Scope         string
	Username      string
	Password      string
	AssertionType string
	Assertion     string

	// Token expiration in seconds. Change if different from default
	Expiration int32

	// Set if a refresh token should be generated
	GenerateRefresh bool

	// Data to be passed to storage. Not used by the library.
	UserData interface{}

	// Optional code_verifier as described in rfc7636
	CodeVerifier string
}

AccessRequest is a request for access tokens

type AccessRequestAuthorizedCallback

type AccessRequestAuthorizedCallback func(ar *AccessRequest) (bool, error)

AccessRequestAuthorizedCallback returns if an access request should succeed or access should be denied. errors returned by this function will result in internal server errors being returned

type AccessTokenGenerator

type AccessTokenGenerator interface {
	GenerateAccessToken(ar *AccessData) (string, error)
	GenerateRefreshToken(ar *RefreshTokenData) (string, error)
}

AccessTokenGenerator generates access tokens and refresh tokens

type AccessTokenSubScoper

type AccessTokenSubScoper interface {
	CheckSubScopes(accessTokenScopes string, refreshTokenScopes string) (string, error)
}

AccessTokenSubScoper checks if the requested scopes of AT are a subset of already granted scopes.

type AllowedAccessTypes

type AllowedAccessTypes []GrantType

AllowedAccessTypes is a collection of allowed access request types

func (AllowedAccessTypes) Exists

func (t AllowedAccessTypes) Exists(rt GrantType) bool

Exists returns true if the access type exists in the list

type AllowedAuthorizeTypes

type AllowedAuthorizeTypes []AuthorizeResponseType

AllowedAuthorizeTypes is a collection of allowed auth request types

func (AllowedAuthorizeTypes) Exists

Exists returns true if the auth type exists in the list

type AuthRequestAuthorizedCallback

type AuthRequestAuthorizedCallback func(ar *AuthorizationRequest) (bool, error)

AuthRequestAuthorizedCallback returns if an authorization request should succeed or access should be denied. errors returned by this function will result in internal server errors being returned

type AuthRequestGenerator

type AuthRequestGenerator func() (*AuthorizationRequest, error)

AuthRequestGenerator generates and returns an AuthorizationRequest to process or an error.

type AuthorizationData

type AuthorizationData struct {
	// ClientData information
	ClientID string

	// Authorization code
	Code string

	// Token expiration in seconds
	ExpiresIn int32

	// Requested scope
	Scope string

	// Redirect Uri from request
	RedirectURI string

	// State data from request
	State string

	// Date created
	CreatedAt time.Time

	// Data to be passed to storage. Not used by the library.
	UserData interface{}

	// Optional code_challenge as described in rfc7636
	CodeChallenge string
	// Optional code_challenge_method as described in rfc7636
	CodeChallengeMethod PKCECodeChallengeMethod
}

AuthorizationData represents an issued authorization code

func (*AuthorizationData) ExpireAt

func (d *AuthorizationData) ExpireAt() time.Time

ExpireAt returns the expiration date

func (*AuthorizationData) IsExpiredAt

func (d *AuthorizationData) IsExpiredAt(t time.Time) bool

IsExpiredAt is true if authorization has expired by time 't'

type AuthorizationRequest

type AuthorizationRequest struct {
	ResponseType AuthorizeResponseType
	ClientID     string
	Scope        string
	RedirectURI  string
	State        string

	// Token expiration in seconds. Change if different from default.
	// If type = ResponseTypeToken, this expiration will be for the ACCESS token.
	Expiration int32

	// Optional code_challenge as described in rfc7636
	CodeChallenge string
	// Optional code_challenge_method as described in rfc7636
	CodeChallengeMethod PKCECodeChallengeMethod

	// (optional) Data to be passed to storage. Not used by the library.
	UserData interface{}
}

AuthorizationRequest represents an incoming authorization request

type AuthorizeResponseType

type AuthorizeResponseType string

AuthorizeResponseType is the type for OAuth param `response_type`

const (
	ResponseTypeCode  AuthorizeResponseType = "code"
	ResponseTypeToken AuthorizeResponseType = "token"
)

AuthorizeResponseType is either code or token

type AuthorizeTokenGenerator

type AuthorizeTokenGenerator interface {
	GenerateAuthorizeToken(data *AuthorizationData) (string, error)
}

AuthorizeTokenGenerator is the token generator interface

type BasicAuth

type BasicAuth struct {
	Username string
	Password string
}

BasicAuth is the parsed basic authentication header

type ClientData

type ClientData struct {
	ClientID     string // Unique identifier for this client (https://tools.ietf.org/html/rfc6749#section-2.2)
	ClientSecret string // OAuth2 client secret (https://tools.ietf.org/html/rfc6749#section-2.3.1)
	RedirectURI  string // OAuth2 redirect URI
}

ClientData is the information stored for an OAuth2 client

func (*ClientData) ValidSecret

func (c *ClientData) ValidSecret(secret string) bool

ValidSecret checks if the given secret is valid for this OAuth2 client

type DefaultAccessTokenGenerator

type DefaultAccessTokenGenerator struct {
}

DefaultAccessTokenGenerator is the default authorization token generator

func (*DefaultAccessTokenGenerator) GenerateAccessToken

func (a *DefaultAccessTokenGenerator) GenerateAccessToken(ar *AccessData) (string, error)

GenerateAccessToken generates base64-encoded UUID access and refresh tokens

func (*DefaultAccessTokenGenerator) GenerateRefreshToken

func (a *DefaultAccessTokenGenerator) GenerateRefreshToken(ar *RefreshTokenData) (string, error)

GenerateRefreshToken generates base64-encoded UUID access and refresh tokens

type DefaultAccessTokenSubScoper

type DefaultAccessTokenSubScoper struct {
}

DefaultAccessTokenSubScoper checks if the given scopes of AT request are a string subset of already granted scopes.

func (*DefaultAccessTokenSubScoper) CheckSubScopes

func (a *DefaultAccessTokenSubScoper) CheckSubScopes(accessTokenScopes string, refreshTokenScopes string) (string, error)

CheckSubScopes checks the given access token scopes to see if they are granted by the refresh token's scope, and returns the resulting subset of scopes.

type DefaultAuthorizeTokenGenerator

type DefaultAuthorizeTokenGenerator struct {
}

DefaultAuthorizeTokenGenerator is the default authorization token generator

func (*DefaultAuthorizeTokenGenerator) GenerateAuthorizeToken

func (a *DefaultAuthorizeTokenGenerator) GenerateAuthorizeToken(data *AuthorizationData) (string, error)

GenerateAuthorizeToken generates a base64-encoded UUID code

type Error

type Error struct {
	Code ErrorCode
	Err  error

	// Human readable description of the error that occurred
	Message string
	// contains filtered or unexported fields
}

Error is a wrapper around an existing error with an OAuth2 error code

func NewError

func NewError(code ErrorCode, message string, args ...interface{}) *Error

NewError creates a new Error for a response error code

func NewWrappedError

func NewWrappedError(code ErrorCode, error error, message string, args ...interface{}) *Error

NewWrappedError creates a new Error for a response error code and wraps the original error with the given description

func (*Error) AsResponse

func (e *Error) AsResponse() *Response

AsResponse creates a response object from this error, containing it's body or a redirect if specified

func (*Error) Error

func (e *Error) Error() string

func (*Error) GetRedirectURI

func (e *Error) GetRedirectURI() (string, error)

GetRedirectURI returns location to redirect user to after processing this error, or empty string if there is none

func (*Error) GetResponseDict

func (e *Error) GetResponseDict() map[string]string

GetResponseDict returns the fields for an error response as defined in https://tools.ietf.org/html/rfc6749#section-4.2.2.1

func (*Error) SetRedirectURI

func (e *Error) SetRedirectURI(redirectURI string)

SetRedirectURI set redirect uri for this error to redirect to when written to a HTTP response

func (*Error) SetState

func (e *Error) SetState(state string)

SetState sets the "state" parameter to be returned to the user when this error is rendered

type ErrorCode

type ErrorCode string

ErrorCode is an OAuth2 error code

const (
	EInvalidRequest          ErrorCode = "invalid_request"
	EUnauthorizedClient      ErrorCode = "unauthorized_client"
	EAccessDenied            ErrorCode = "access_denied"
	EUnsupportedResponseType ErrorCode = "unsupported_response_type"
	EInvalidScope            ErrorCode = "invalid_scope"
	EServerError             ErrorCode = "server_error"
	ETemporarilyUnavailable  ErrorCode = "temporarily_unavailable"
	EUnsupportedGrantType    ErrorCode = "unsupported_grant_type"
	EInvalidGrant            ErrorCode = "invalid_grant"
	EInvalidClient           ErrorCode = "invalid_client"
)

OAuth2 error codes (https://tools.ietf.org/html/rfc6749#section-4.1.2.1)

type GrantType

type GrantType string

GrantType is the type for OAuth param `grant_type`

const (
	GrantTypeAuthorizationCode GrantType = "authorization_code"
	GrantTypeRefreshToken      GrantType = "refresh_token"
	GrantTypePassword          GrantType = "password"
	GrantTypeClientCredentials GrantType = "client_credentials"
	GrantTypeImplicit          GrantType = "__implicit"
)

https://tools.ietf.org/html/rfc6749#appendix-A.10

type NotFoundError

type NotFoundError struct {
	Err error
}

NotFoundError can be used to differentiate between internal server errors and an entity not existing in storage.

func (*NotFoundError) Error

func (e *NotFoundError) Error() string

type OnAuthSuccessCallback

type OnAuthSuccessCallback func(ar *AuthorizationRequest, resp *Response) error

OnAuthSuccessCallback is called after an authorize request is successful to allow any final manipulation of the response, whilst still having errors captures and handled as per the OAuth spec.

type PKCECodeChallengeMethod

type PKCECodeChallengeMethod string

PKCECodeChallengeMethod is the code_challenge field as described in rfc7636

type RefreshTokenData

type RefreshTokenData struct {
	// ID of the client used to issue this refresh token
	ClientID string

	// Refresh token string
	RefreshToken string

	// Time at which refresh token was created
	CreatedAt time.Time

	// Redirect Uri from request
	RedirectURI string

	// Scope requested for this refresh token
	Scope string

	// Previous refresh token (if one existed)
	PreviousRefreshToken string

	// Type of grant used to issue this token
	GrantedVia GrantType

	// Data to be passed to storage. Not used by the library.
	UserData interface{}
}

RefreshTokenData represents an issued refresh token, which should be persisted to storage in it's entirety

type Response

type Response struct {
	StatusCode int
	Data       ResponseData
	Headers    http.Header
	// contains filtered or unexported fields
}

Response represents a HTTP response to be sent to the user

func NewResponse

func NewResponse() *Response

NewResponse creates a new empty response

func (*Response) GetRedirectURL

func (r *Response) GetRedirectURL() (string, error)

GetRedirectURL returns the redirect url with all query string parameters

func (*Response) SetRedirectFragment

func (r *Response) SetRedirectFragment(f bool)

SetRedirectFragment sets redirect values to be passed in fragment instead of as query parameters

func (*Response) SetRedirectURL

func (r *Response) SetRedirectURL(url string)

SetRedirectURL changes the response to redirect to the given url

type ResponseData

type ResponseData map[string]interface{}

ResponseData is the data to be serialized for response output

type ResponseType

type ResponseType int

ResponseType enum indicates type of response

const (
	DATA ResponseType = iota
	REDIRECT
)

Responses can either be data (an have a body to to be serialized) or are a redirect.

type Server

type Server struct {
	Config                  *ServerConfig
	Storage                 Storage
	AuthorizeTokenGenerator AuthorizeTokenGenerator
	AccessTokenGenerator    AccessTokenGenerator
	AccessTokenSubScoper    AccessTokenSubScoper
	Now                     func() time.Time
}

Server is an OAuth2 implementation

func NewServer

func NewServer(config *ServerConfig, storage Storage) *Server

NewServer creates a new server instance

func (*Server) FinishAccessRequest

func (s *Server) FinishAccessRequest(ctx context.Context, ar *AccessRequest) (*Response, error)

FinishAccessRequest processes a given access request and returns the response or error to return to the user

func (*Server) FinishAuthorizeRequest

func (s *Server) FinishAuthorizeRequest(ctx context.Context, ar *AuthorizationRequest) (*Response, error)

FinishAuthorizeRequest takes in a authorization request and returns a response to the client or an error

func (*Server) GenerateAccessRequest

func (s *Server) GenerateAccessRequest(ctx context.Context, r *http.Request) (*AccessRequest, error)

GenerateAccessRequest generates an AccessRequest from a HTTP request.

func (*Server) GenerateAuthorizationRequest

func (s *Server) GenerateAuthorizationRequest(ctx context.Context, r *http.Request) (*AuthorizationRequest, error)

GenerateAuthorizationRequest handles authorization requests. Generates an AuthorizationRequest from a HTTP request.

func (*Server) HandleAuthorizeRequest

func (s *Server) HandleAuthorizeRequest(
	ctx context.Context,
	f AuthRequestGenerator,
	isAuthorizedCb AuthRequestAuthorizedCallback,
	onSuccessCb OnAuthSuccessCallback,
) (*Response, error)

HandleAuthorizeRequest is the main entry point for handling authorization requests. It can take a method which generates the AuthRequest struct to use for the authorization This method will always return a Response, even if there was an error processing the request, which should be rendered for a user. It may also return an error in the second argument which can be logged by the caller.

func (*Server) HandleHTTPAccessRequest

func (s *Server) HandleHTTPAccessRequest(r *http.Request, isAuthorizedCb AccessRequestAuthorizedCallback) (*Response, error)

HandleHTTPAccessRequest is the main entry point for handling access requests. This method will always return a Response, even if there was an error processing the request, which should be rendered for a user. It may also return an error in the second argument which can be logged by the caller.

func (*Server) HandleHTTPAuthorizeRequest

func (s *Server) HandleHTTPAuthorizeRequest(r *http.Request, isAuthorizedCb AuthRequestAuthorizedCallback) (*Response, error)

HandleHTTPAuthorizeRequest is the main entry point for handling authorization requests. This method will always return a Response, even if there was an error processing the request, which should be rendered for a user. It may also return an error in the second argument which can be logged by the caller.

type ServerConfig

type ServerConfig struct {
	// Authorization token expiration in seconds (default 5 minutes)
	AuthorizationExpiration int32

	// Access token expiration in seconds (default 1 hour)
	AccessExpiration int32

	// Token type to return
	TokenType string

	// List of allowed authorize types (only ResponseTypeCode by default)
	AllowedAuthorizeTypes AllowedAuthorizeTypes

	// List of allowed access types (only GrantTypeAuthorizationCode by default)
	AllowedAccessTypes AllowedAccessTypes

	// If true allows client secret also in params, else only in
	// Authorization header - default false
	AllowClientSecretInParams bool

	// Require PKCE for code flows for public OAuth clients - default false
	RequirePKCEForPublicClients bool

	// Separator to support multiple URIs in ClientData.GetRedirectURI().
	// If blank (the default), don't allow multiple URIs.
	RedirectURISeparator string

	// If true allows access request using GET, else only POST - default false
	AllowGetAccessRequest bool
}

ServerConfig contains server configuration information

func NewServerConfig

func NewServerConfig() *ServerConfig

NewServerConfig returns a new ServerConfig with default configuration

type Storage

type Storage interface {
	// Close the resources the Storage potentially holds. (Implements io.Closer)
	Close() error

	// GetClientData fetches the data for a ClientData by id
	// Should return NotFoundError, so an EInvalidClient error will be returned instead of EServerError
	GetClientData(ctx context.Context, id string) (*ClientData, error)

	// GetAuthorizeData looks up AuthorizationData by a code.
	//// ClientData information MUST be loaded together.
	// Optionally can return error if expired.
	GetAuthorizeData(ctx context.Context, code string) (*AuthorizationData, error)

	// SaveAuthorizeData saves authorize data.
	SaveAuthorizeData(ctx context.Context, data *AuthorizationData) error

	// DeleteAuthorizeData revokes or deletes the authorization code.
	DeleteAuthorizeData(ctx context.Context, code string) error

	// SaveAccessData writes AccessData to storage.
	SaveAccessData(ctx context.Context, data *AccessData) error

	// GetRefreshTokenData retrieves refresh token data from the token string.
	GetRefreshTokenData(ctx context.Context, token string) (*RefreshTokenData, error)

	// SaveRefreshTokenData saves refresh token data so it can be retrieved with GetRefreshTokenData
	SaveRefreshTokenData(ctx context.Context, data *RefreshTokenData) error

	// DeleteRefreshTokenData revokes or deletes a RefreshToken.
	DeleteRefreshTokenData(ctx context.Context, token string) error
}

Storage is a backend used to persist data generated by the OAuth2 server

type URIValidationError

type URIValidationError string

URIValidationError is an error returned when a URI is invalid or does not match any URIs provided in the allowed URI list

func (URIValidationError) Error

func (e URIValidationError) Error() string

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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