Documentation
¶
Overview ¶
Package multipass implements an authentication service which can be used to wrap any http.Handler(Func).
Multipass implements the concept to authenticate users based on something they own instead of something they know. This is better known as the second factor of Two-factor Authentication.
Quick Start ¶
Wrap any http.Handler or http.HandlerFunc to provide user authentication. In the example below, the appHandler function is wrapped using the AuthHandler wrapper. It assumes you have a SMTP service running on `localhost:2525` and user identified by email address leeloo@dallas has access to the resource at `/private`.
package main import ( "fmt" "log" "net/http" "github.com/namsral/multipass" "github.com/namsral/multipass/services/email" ) func appHandler(w http.ResponseWriter, r *http.Request) { handle := r.Header.Get("Multipass-Handle") if len(handle) == 0 { handle = "anonymous" } switch r.URL.Path { case "/", "/private": fmt.Fprintf(w, "Hello %s, welcome to %s", handle, r.URL.Path) return } http.NotFound(w, r) } func main() { service, err := email.NewUserService(email.Options{ SMTPAddr: "localhost:2525", FromAddr: "Multipass Bot <noreply@dallas>", }) if err != nil { log.Fatal(err) } service.AddHandle("leeloo@dallas") // Register user service.AddResource("/private") // Make resource private addr := "localhost:6080" siteaddr := "http://" + addr m := multipass.New(siteaddr, multipass.Service(service)) h := multipass.AuthHandler(http.HandlerFunc(appHandler), m) log.Fatal(http.ListenAndServe(addr, h)) }
The package consist of three major components; Multipass, ResourceHandler and UserService.
Multipass ¶
Multipass is a http.Handler which issues and signs user tokens and validates their signature.
func New(siteaddr string, opts ...Option) *Multipass {
Multipass has it's own web UI which is available at the configurable basepath. From the web UI users can request a login url to gain access to private resources.
UserService ¶
User authorization is offloaded to the UserService service. Because the UserService is an interface custom UserService's can be developed and plugged into the Multipass instance. Allowing other means of authentication and authorization besides the built-in email UserService.
// UserService is an interface used by the Multipass instance to query about // listed handles, authorized resource access and to notify users about login // urls. A handle is a unique user identifier, e.g. username, email address. type UserService interface { // Listed returns true when the given handle is listed with the // service. Listed(handle string) bool // Authorized returns true when the user identified by the given handle is // authorized to access the given resource at rawurl with the given method. Authorized(handle, method, rawurl string) bool // Notify returns nil when the given login URL is successfully // communicated to the given handle. Notify(handle, loginurl string) error // Close closes any open connections. Close() error }
An implementation can be found in the `services/email` package. This implementations identifies users by their email address.
ResourceHandler ¶
ResourceHandler accepts a http.ResponseWriter and http.Request and determines if the request is from an authenticated user and if this user is authorized to access the requested resource according to the UserService. The ResourceHandler extracts any user token from the header, cookie header or query parameters and validates the user tokens signature with preset or pre-generated key pairs.
func ResourceHandler(w http.ResponseWriter, r *http.Request, m *Multipass) (int, error) {
Index ¶
- Constants
- Variables
- func AuthHandler(next http.Handler, m *Multipass) http.Handler
- func ConcatonateHeader(h http.Header) []byte
- func GetTokenRequest(r *http.Request) string
- func NewLoginURL(siteaddr, Basepath, token string, v url.Values) (*url.URL, error)
- func PrivateKeyFromEnvironment() (*rsa.PrivateKey, error)
- func ResourceHandler(w http.ResponseWriter, r *http.Request, m *Multipass) (int, error)
- func SignHeader(h http.Header, key *rsa.PrivateKey) error
- func VerifySignedHeader(h http.Header, key *rsa.PublicKey) error
- type Claims
- type Multipass
- type Option
- type UserService
Constants ¶
const ( DefaultDigest = "SHA256" DefaultAlgo = "RSASSA-PSS" DefaultKeySize = 2048 )
Portable constants
const (
PKENV = "MULTIPASS_RSA_PRIVATE_KEY"
)
Portable constants
Variables ¶
var ( ErrInvalidToken = errors.New("invalid token") ErrForbidden = errors.New(http.StatusText(http.StatusForbidden)) )
Portable errors
var (
ErrInvalidSignature = errors.New("invalid signature")
)
Portable errors
Functions ¶
func AuthHandler ¶ added in v0.3.0
AuthHandler wraps any http.Handler to provide authentication using the given Multipass instance. Handlers from other http routers can be wrapped with little effort by copying the AuthHandler and make minor changes.
func ConcatonateHeader ¶ added in v0.4.0
ConcatonateHeader returns concatination of the given headers. Headers are sorted, trimmed of whitespace, and converted to lowercase. Multiple headers with the same name are joined using commas to separate values.
func GetTokenRequest ¶ added in v0.4.0
GetTokenRequest returns the JWT token embedded in the given request. JWT tokens can be embedded in the header prefixed with "Bearer ", with a "token" key query parameter or a cookie named "jwt_token".
func NewLoginURL ¶
NewLoginURL returns a login url which can be used as a time limited login. Optional values will be encoded in the login URL.
func PrivateKeyFromEnvironment ¶ added in v0.4.0
func PrivateKeyFromEnvironment() (*rsa.PrivateKey, error)
PrivateKeyFromEnvironment returns the private key as indicated by the environment variable MULTIPASS_RSA_PRIVATE_KEY. The environment value must be a PEM encoding key starting with "-----BEGIN RSA PRIVATE KEY-----".
A nil PrivateKey and nil error are returned if no private key is found in the environment variable value.
func ResourceHandler ¶ added in v0.3.0
ResourceHandler validates the token in the request before it writes the response. It adds the user handle if the user is authenticated and signs the any Multipass specific headers.
func SignHeader ¶ added in v0.4.0
func SignHeader(h http.Header, key *rsa.PrivateKey) error
SignHeader signs the given header and adds the key with name "Multipass-Signature". The signature is generated using the RSA_PSS algorithm and sha-256 digest.
Types ¶
type Multipass ¶
type Multipass struct {
// contains filtered or unexported fields
}
Multipass implements the http.Handler interface which can handle authentication and authorization of users and resources using signed JWT.
func New ¶ added in v0.4.0
New returns a new instance of Multipass with the given site address.
The site address must point to the absolute base URL of the site.
Multipass is initialized with the following defaults:
2048 bit key size /multipass Basepath 24h token lifespan
func (*Multipass) AccessToken ¶
AccessToken returns a new signed and serialized token with the given handle as a claim.
type Option ¶ added in v0.4.0
type Option func(*Multipass)
Option describes a functional option for configuring the Multipass instance.
func Basepath ¶ added in v0.4.0
Basepath overrides the default base path of `/multipass`. The given basepath is made absolute before it is set.
func CSRF ¶ added in v0.4.0
CSRF sets a bool wether to protect against CSRF attaks. The default is true.
func Expires ¶ added in v0.4.0
Expires sets the maximum age for JWT tokens. When a token exceeds the maximum age it is no longer valid.
func Service ¶ added in v0.4.0
func Service(s UserService) Option
Service sets the UserService and overrides DefaultUserService.
type UserService ¶ added in v0.3.0
type UserService interface { // Listed returns true when the given handle is listed with the // service. Listed(handle string) bool // Authorized returns true when the user identified by the given handle is // authorized to access the given resource at rawurl with the given method. Authorized(handle, method, rawurl string) bool // Notify returns nil when the given login URL is successfully // communicated to the given handle. Notify(handle, loginurl string) error // Close closes any open connections. Close() error }
UserService is an interface used by the Multipass instance to query about listed handles, authorized resource access and to notify users about login urls. A handle is a unique user identifier, e.g. username, email address.