turtle

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

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

Go to latest
Published: Jan 3, 2017 License: MIT Imports: 7 Imported by: 0

README

turtle

HandlerFunc all the way down.

Example

The following uses gorilla router, but anything taking a HandlerFunc will work with turtle.Bundle.

package main

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

	jwt "github.com/dgrijalva/jwt-go"
	"github.com/gorilla/mux"
	"github.com/stacktitan/turtle"
	"github.com/stacktitan/turtle/schemes"
)

type User struct {
	Username string
	Roles    []string
}

// Implements Roler.
func (u User) HasRole(role string) bool {
	for _, r := range u.Roles {
		if r == role {
			return true
		}
	}
	return false
}

var user = User{
	Username: "alice",
	Roles:    []string{"user"},
}

func main() {

	bundle := turtle.NewBundler()
	bundle.RegisterScheme("jwt", &schemes.JWTScheme{
		Secret: []byte("password"),
		ValidateFunc: func(claims jwt.MapClaims) (interface{}, error) {
			username, ok := claims["username"].(string)
			if !ok {
				return nil, errors.New("no username in token")
			}
			if username != user.Username {
				return nil, errors.New("user not found")
			}
			return user, nil
		},
	})
	bundle.SetDefaultScheme("jwt") // Every request will require jwt scheme, unless AuthMode none.
	router := mux.NewRouter()
	router.HandleFunc("/token", bundle.New(turtle.O{
		Allow:    []string{"application/json"}, // Only allow JSON.
		AuthMode: "none",                       // Disable authentication for this route.
		HandlerFunc: func(w http.ResponseWriter, r *http.Request) {
			// Here is where you would probably decode username and password and validate.
			token := jwt.New(jwt.SigningMethodHS512)
			claims := jwt.MapClaims{}
			claims["username"] = user.Username
			token.Claims = claims
			s, _ := token.SignedString([]byte("password"))
			fmt.Fprintf(w, "token: %s", s)
		},
	})).Methods("POST")
	router.HandleFunc("/me", bundle.New(turtle.O{
		AuthMode: "required",
		Roles:    []string{"user"}, // Roles can be used to restrict access.
		Schemes:  []string{"jwt"},  // Schemes can be set per HandleFunc.
		HandlerFunc: func(w http.ResponseWriter, r *http.Request) {
			// Authentication schemes mount credentials in the request context.
			u := r.Context().Value(turtle.CtxCredentials{}).(User)
			fmt.Fprintf(w, "username: %s", u.Username)
		},
	})).Methods("GET")

	log.Fatal(http.ListenAndServe(":3000", router))
}

/token requires JSON.

$ curl http://localhost:3000/token -X POST -H "Content-Type: application/json"
token: eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFsaWNlIn0.DIUMnDYOs1tti1aAEHXBdmdzqqrWYWGYSVWy4Q63RxeiCSLAXaJPXHWDQ-fi8tsuv1TdhIar3J14PtG5b8TKOw

All errors are written by default using JSON and boom.Error using the DefaultErrorWriter.

Bad content-type:

$ curl -ki http://localhost:3000/token -X POST -H "Content-Type: text/plain"
HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=UTF-8
Date: Sat, 31 Dec 2016 06:01:31 GMT
Content-Length: 104

{"status_code":400,"error":"Bad Request","message":"invalid request content-type: text/plain","data":{}}

Authentication on all handlers will be required using the default scheme. And all routes require an AuthMode.

$ curl http://localhost:3000/me -H 'Authorization: bearer eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFsaWNlIn0.DIUMnDYOs1tti1aAEHXBdmdzqqrWYWGYSVWy4Q63RxeiCS
LAXaJPXHWDQ-fi8tsuv1TdhIar3J14PtG5b8TKOw'
username: alice

If authentication or validation fails:

$ curl -ki http://localhost:3000/me
HTTP/1.1 401 Unauthorized
Content-Type: application/json; charset=UTF-8
Date: Sat, 31 Dec 2016 06:02:08 GMT
Content-Length: 65

{"status_code":401,"error":"Unauthorized","message":"","data":{}}

Documentation

Index

Constants

View Source
const (
	AUTHMODEREQUIRED = "required"
	AUTMODETRY       = "try"
	AUTHMODENONE     = "none"
)

AuthMode constants.

Variables

This section is empty.

Functions

This section is empty.

Types

type Bundler

type Bundler struct {
	EW ErrorWriter
	// contains filtered or unexported fields
}

Bundler bundles authentication, authorization, validation and per HandlerFunc logic into a nice package.

func NewBundler

func NewBundler() *Bundler

NewBundler returns a new Bundler.

func (*Bundler) New

func (b *Bundler) New(options O) func(http.ResponseWriter, *http.Request)

New returns a bundled HandlerFunc. New may panic if options are incorrect that could result in a invalid or insecure configuration.

func (*Bundler) RegisterScheme

func (b *Bundler) RegisterScheme(name string, scheme Scheme)

RegisterScheme registers the scheme by name with bundler. It can then be used in O.Schemes.

func (*Bundler) SetDefaultScheme

func (b *Bundler) SetDefaultScheme(name string) error

SetDefaultScheme sets the scheme name that will be used for every bundled HandlerFunc. Error will be returned if the scheme has not been registered.

type CtxCredentials

type CtxCredentials struct{}

CtxCredentials is the key for the request context value holding credentials returned from Scheme.Authenticate.

type DefaultErrorWriter

type DefaultErrorWriter struct {
	// contains filtered or unexported fields
}

DefaultErrorWriter is the default ErrorWriter used by Bundler.

func (DefaultErrorWriter) WriteError

func (d DefaultErrorWriter) WriteError(w http.ResponseWriter, _ *http.Request, err error)

WriteError writes an error to the ResponseWriter as JSON.

type ErrorWriter

type ErrorWriter interface {
	WriteError(w http.ResponseWriter, r *http.Request, err error)
}

ErrorWriter implements error handling for bundles HandlerFunc. err is a boom.Error and has information such as status codes. Seee DefaultErrorWriter for implementation details.

type HandleWrap

type HandleWrap func(func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request)

HandleWrap is a function that takes a HandlerFunc and returns a HandlerFunc.

func WrapSlice

func WrapSlice(funcs ...HandleWrap) []HandleWrap

WrapSlice takes a variable amount of HandleWraps and returns a slice. This is a convienience function for setting O.Before.

type O

type O struct {
	Allow       []string     // Content-Types to allow.
	Roles       []string     // Roles to allow, object in request context with key CtxCredentials must implement Roler.
	Schemes     []string     // A series of authentication schemes to try in order. Must be registered with Bundler.
	AuthMode    string       // 'try', 'required', 'none'.
	Before      []HandleWrap // A series of HandlerFuncs to execute before Handle.
	After       []HandleWrap // A serios of HandlerFuncs to execute after Handle.
	HandlerFunc func(http.ResponseWriter, *http.Request)
}

O are options to pass to Bundle.

type Roler

type Roler interface {
	HasRole(role string) bool
}

Roler is in interface used during authorization to validate that the implementer has the required role.

type Scheme

type Scheme interface {
	Authenticate(w http.ResponseWriter, r *http.Request) (interface{}, error)
}

Scheme is an abstraction layer around a session management and authentication scheme. Authenticate should authenticate a request and return credentials or an error. Any presence of an error will indicate an authentication failure.

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

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