Vendor dependencies

This commit is contained in:
Jonas Franz 2020-06-26 11:11:27 +02:00
parent d2d6f8cacd
commit b64bbcbd7e
Signed by: JonasFranz
GPG Key ID: 7293A220B7C38080
245 changed files with 32476 additions and 0 deletions

9
vendor/github.com/google/uuid/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,9 @@
language: go
go:
- 1.4.3
- 1.5.3
- tip
script:
- go test -v ./...

10
vendor/github.com/google/uuid/CONTRIBUTING.md generated vendored Normal file
View File

@ -0,0 +1,10 @@
# How to contribute
We definitely welcome patches and contribution to this project!
### Legal requirements
In order to protect both you and ourselves, you will need to sign the
[Contributor License Agreement](https://cla.developers.google.com/clas).
You may have already signed it for other Google projects.

9
vendor/github.com/google/uuid/CONTRIBUTORS generated vendored Normal file
View File

@ -0,0 +1,9 @@
Paul Borman <borman@google.com>
bmatsuo
shawnps
theory
jboverfelt
dsymonds
cd1
wallclockbuilder
dansouza

27
vendor/github.com/google/uuid/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright (c) 2009,2014 Google Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

19
vendor/github.com/google/uuid/README.md generated vendored Normal file
View File

@ -0,0 +1,19 @@
# uuid ![build status](https://travis-ci.org/google/uuid.svg?branch=master)
The uuid package generates and inspects UUIDs based on
[RFC 4122](http://tools.ietf.org/html/rfc4122)
and DCE 1.1: Authentication and Security Services.
This package is based on the github.com/pborman/uuid package (previously named
code.google.com/p/go-uuid). It differs from these earlier packages in that
a UUID is a 16 byte array rather than a byte slice. One loss due to this
change is the ability to represent an invalid UUID (vs a NIL UUID).
###### Install
`go get github.com/google/uuid`
###### Documentation
[![GoDoc](https://godoc.org/github.com/google/uuid?status.svg)](http://godoc.org/github.com/google/uuid)
Full `go doc` style documentation for the package can be viewed online without
installing this package by using the GoDoc site here:
http://godoc.org/github.com/google/uuid

80
vendor/github.com/google/uuid/dce.go generated vendored Normal file
View File

@ -0,0 +1,80 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"encoding/binary"
"fmt"
"os"
)
// A Domain represents a Version 2 domain
type Domain byte
// Domain constants for DCE Security (Version 2) UUIDs.
const (
Person = Domain(0)
Group = Domain(1)
Org = Domain(2)
)
// NewDCESecurity returns a DCE Security (Version 2) UUID.
//
// The domain should be one of Person, Group or Org.
// On a POSIX system the id should be the users UID for the Person
// domain and the users GID for the Group. The meaning of id for
// the domain Org or on non-POSIX systems is site defined.
//
// For a given domain/id pair the same token may be returned for up to
// 7 minutes and 10 seconds.
func NewDCESecurity(domain Domain, id uint32) (UUID, error) {
uuid, err := NewUUID()
if err == nil {
uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2
uuid[9] = byte(domain)
binary.BigEndian.PutUint32(uuid[0:], id)
}
return uuid, err
}
// NewDCEPerson returns a DCE Security (Version 2) UUID in the person
// domain with the id returned by os.Getuid.
//
// NewDCESecurity(Person, uint32(os.Getuid()))
func NewDCEPerson() (UUID, error) {
return NewDCESecurity(Person, uint32(os.Getuid()))
}
// NewDCEGroup returns a DCE Security (Version 2) UUID in the group
// domain with the id returned by os.Getgid.
//
// NewDCESecurity(Group, uint32(os.Getgid()))
func NewDCEGroup() (UUID, error) {
return NewDCESecurity(Group, uint32(os.Getgid()))
}
// Domain returns the domain for a Version 2 UUID. Domains are only defined
// for Version 2 UUIDs.
func (uuid UUID) Domain() Domain {
return Domain(uuid[9])
}
// ID returns the id for a Version 2 UUID. IDs are only defined for Version 2
// UUIDs.
func (uuid UUID) ID() uint32 {
return binary.BigEndian.Uint32(uuid[0:4])
}
func (d Domain) String() string {
switch d {
case Person:
return "Person"
case Group:
return "Group"
case Org:
return "Org"
}
return fmt.Sprintf("Domain%d", int(d))
}

12
vendor/github.com/google/uuid/doc.go generated vendored Normal file
View File

@ -0,0 +1,12 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package uuid generates and inspects UUIDs.
//
// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security
// Services.
//
// A UUID is a 16 byte (128 bit) array. UUIDs may be used as keys to
// maps or compared directly.
package uuid

1
vendor/github.com/google/uuid/go.mod generated vendored Normal file
View File

@ -0,0 +1 @@
module github.com/google/uuid

53
vendor/github.com/google/uuid/hash.go generated vendored Normal file
View File

@ -0,0 +1,53 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"crypto/md5"
"crypto/sha1"
"hash"
)
// Well known namespace IDs and UUIDs
var (
NameSpaceDNS = Must(Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8"))
NameSpaceURL = Must(Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8"))
NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8"))
NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8"))
Nil UUID // empty UUID, all zeros
)
// NewHash returns a new UUID derived from the hash of space concatenated with
// data generated by h. The hash should be at least 16 byte in length. The
// first 16 bytes of the hash are used to form the UUID. The version of the
// UUID will be the lower 4 bits of version. NewHash is used to implement
// NewMD5 and NewSHA1.
func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
h.Reset()
h.Write(space[:])
h.Write(data)
s := h.Sum(nil)
var uuid UUID
copy(uuid[:], s)
uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4)
uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant
return uuid
}
// NewMD5 returns a new MD5 (Version 3) UUID based on the
// supplied name space and data. It is the same as calling:
//
// NewHash(md5.New(), space, data, 3)
func NewMD5(space UUID, data []byte) UUID {
return NewHash(md5.New(), space, data, 3)
}
// NewSHA1 returns a new SHA1 (Version 5) UUID based on the
// supplied name space and data. It is the same as calling:
//
// NewHash(sha1.New(), space, data, 5)
func NewSHA1(space UUID, data []byte) UUID {
return NewHash(sha1.New(), space, data, 5)
}

37
vendor/github.com/google/uuid/marshal.go generated vendored Normal file
View File

@ -0,0 +1,37 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import "fmt"
// MarshalText implements encoding.TextMarshaler.
func (uuid UUID) MarshalText() ([]byte, error) {
var js [36]byte
encodeHex(js[:], uuid)
return js[:], nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (uuid *UUID) UnmarshalText(data []byte) error {
id, err := ParseBytes(data)
if err == nil {
*uuid = id
}
return err
}
// MarshalBinary implements encoding.BinaryMarshaler.
func (uuid UUID) MarshalBinary() ([]byte, error) {
return uuid[:], nil
}
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
func (uuid *UUID) UnmarshalBinary(data []byte) error {
if len(data) != 16 {
return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
}
copy(uuid[:], data)
return nil
}

89
vendor/github.com/google/uuid/node.go generated vendored Normal file
View File

@ -0,0 +1,89 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"sync"
)
var (
nodeMu sync.Mutex
ifname string // name of interface being used
nodeID [6]byte // hardware for version 1 UUIDs
zeroID [6]byte // nodeID with only 0's
)
// NodeInterface returns the name of the interface from which the NodeID was
// derived. The interface "user" is returned if the NodeID was set by
// SetNodeID.
func NodeInterface() string {
defer nodeMu.Unlock()
nodeMu.Lock()
return ifname
}
// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs.
// If name is "" then the first usable interface found will be used or a random
// Node ID will be generated. If a named interface cannot be found then false
// is returned.
//
// SetNodeInterface never fails when name is "".
func SetNodeInterface(name string) bool {
defer nodeMu.Unlock()
nodeMu.Lock()
return setNodeInterface(name)
}
func setNodeInterface(name string) bool {
iname, addr := getHardwareInterface(name) // null implementation for js
if iname != "" && addr != nil {
ifname = iname
copy(nodeID[:], addr)
return true
}
// We found no interfaces with a valid hardware address. If name
// does not specify a specific interface generate a random Node ID
// (section 4.1.6)
if name == "" {
randomBits(nodeID[:])
return true
}
return false
}
// NodeID returns a slice of a copy of the current Node ID, setting the Node ID
// if not already set.
func NodeID() []byte {
defer nodeMu.Unlock()
nodeMu.Lock()
if nodeID == zeroID {
setNodeInterface("")
}
nid := nodeID
return nid[:]
}
// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes
// of id are used. If id is less than 6 bytes then false is returned and the
// Node ID is not set.
func SetNodeID(id []byte) bool {
if len(id) < 6 {
return false
}
defer nodeMu.Unlock()
nodeMu.Lock()
copy(nodeID[:], id)
ifname = "user"
return true
}
// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is
// not valid. The NodeID is only well defined for version 1 and 2 UUIDs.
func (uuid UUID) NodeID() []byte {
var node [6]byte
copy(node[:], uuid[10:])
return node[:]
}

12
vendor/github.com/google/uuid/node_js.go generated vendored Normal file
View File

@ -0,0 +1,12 @@
// Copyright 2017 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build js
package uuid
// getHardwareInterface returns nil values for the JS version of the code.
// This remvoves the "net" dependency, because it is not used in the browser.
// Using the "net" library inflates the size of the transpiled JS code by 673k bytes.
func getHardwareInterface(name string) (string, []byte) { return "", nil }

33
vendor/github.com/google/uuid/node_net.go generated vendored Normal file
View File

@ -0,0 +1,33 @@
// Copyright 2017 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !js
package uuid
import "net"
var interfaces []net.Interface // cached list of interfaces
// getHardwareInterface returns the name and hardware address of interface name.
// If name is "" then the name and hardware address of one of the system's
// interfaces is returned. If no interfaces are found (name does not exist or
// there are no interfaces) then "", nil is returned.
//
// Only addresses of at least 6 bytes are returned.
func getHardwareInterface(name string) (string, []byte) {
if interfaces == nil {
var err error
interfaces, err = net.Interfaces()
if err != nil {
return "", nil
}
}
for _, ifs := range interfaces {
if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) {
return ifs.Name, ifs.HardwareAddr
}
}
return "", nil
}

59
vendor/github.com/google/uuid/sql.go generated vendored Normal file
View File

@ -0,0 +1,59 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"database/sql/driver"
"fmt"
)
// Scan implements sql.Scanner so UUIDs can be read from databases transparently
// Currently, database types that map to string and []byte are supported. Please
// consult database-specific driver documentation for matching types.
func (uuid *UUID) Scan(src interface{}) error {
switch src := src.(type) {
case nil:
return nil
case string:
// if an empty UUID comes from a table, we return a null UUID
if src == "" {
return nil
}
// see Parse for required string format
u, err := Parse(src)
if err != nil {
return fmt.Errorf("Scan: %v", err)
}
*uuid = u
case []byte:
// if an empty UUID comes from a table, we return a null UUID
if len(src) == 0 {
return nil
}
// assumes a simple slice of bytes if 16 bytes
// otherwise attempts to parse
if len(src) != 16 {
return uuid.Scan(string(src))
}
copy((*uuid)[:], src)
default:
return fmt.Errorf("Scan: unable to scan type %T into UUID", src)
}
return nil
}
// Value implements sql.Valuer so that UUIDs can be written to databases
// transparently. Currently, UUIDs map to strings. Please consult
// database-specific driver documentation for matching types.
func (uuid UUID) Value() (driver.Value, error) {
return uuid.String(), nil
}

123
vendor/github.com/google/uuid/time.go generated vendored Normal file
View File

@ -0,0 +1,123 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"encoding/binary"
"sync"
"time"
)
// A Time represents a time as the number of 100's of nanoseconds since 15 Oct
// 1582.
type Time int64
const (
lillian = 2299160 // Julian day of 15 Oct 1582
unix = 2440587 // Julian day of 1 Jan 1970
epoch = unix - lillian // Days between epochs
g1582 = epoch * 86400 // seconds between epochs
g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs
)
var (
timeMu sync.Mutex
lasttime uint64 // last time we returned
clockSeq uint16 // clock sequence for this run
timeNow = time.Now // for testing
)
// UnixTime converts t the number of seconds and nanoseconds using the Unix
// epoch of 1 Jan 1970.
func (t Time) UnixTime() (sec, nsec int64) {
sec = int64(t - g1582ns100)
nsec = (sec % 10000000) * 100
sec /= 10000000
return sec, nsec
}
// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and
// clock sequence as well as adjusting the clock sequence as needed. An error
// is returned if the current time cannot be determined.
func GetTime() (Time, uint16, error) {
defer timeMu.Unlock()
timeMu.Lock()
return getTime()
}
func getTime() (Time, uint16, error) {
t := timeNow()
// If we don't have a clock sequence already, set one.
if clockSeq == 0 {
setClockSequence(-1)
}
now := uint64(t.UnixNano()/100) + g1582ns100
// If time has gone backwards with this clock sequence then we
// increment the clock sequence
if now <= lasttime {
clockSeq = ((clockSeq + 1) & 0x3fff) | 0x8000
}
lasttime = now
return Time(now), clockSeq, nil
}
// ClockSequence returns the current clock sequence, generating one if not
// already set. The clock sequence is only used for Version 1 UUIDs.
//
// The uuid package does not use global static storage for the clock sequence or
// the last time a UUID was generated. Unless SetClockSequence is used, a new
// random clock sequence is generated the first time a clock sequence is
// requested by ClockSequence, GetTime, or NewUUID. (section 4.2.1.1)
func ClockSequence() int {
defer timeMu.Unlock()
timeMu.Lock()
return clockSequence()
}
func clockSequence() int {
if clockSeq == 0 {
setClockSequence(-1)
}
return int(clockSeq & 0x3fff)
}
// SetClockSequence sets the clock sequence to the lower 14 bits of seq. Setting to
// -1 causes a new sequence to be generated.
func SetClockSequence(seq int) {
defer timeMu.Unlock()
timeMu.Lock()
setClockSequence(seq)
}
func setClockSequence(seq int) {
if seq == -1 {
var b [2]byte
randomBits(b[:]) // clock sequence
seq = int(b[0])<<8 | int(b[1])
}
oldSeq := clockSeq
clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant
if oldSeq != clockSeq {
lasttime = 0
}
}
// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in
// uuid. The time is only defined for version 1 and 2 UUIDs.
func (uuid UUID) Time() Time {
time := int64(binary.BigEndian.Uint32(uuid[0:4]))
time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32
time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48
return Time(time)
}
// ClockSequence returns the clock sequence encoded in uuid.
// The clock sequence is only well defined for version 1 and 2 UUIDs.
func (uuid UUID) ClockSequence() int {
return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff
}

43
vendor/github.com/google/uuid/util.go generated vendored Normal file
View File

@ -0,0 +1,43 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"io"
)
// randomBits completely fills slice b with random data.
func randomBits(b []byte) {
if _, err := io.ReadFull(rander, b); err != nil {
panic(err.Error()) // rand should never fail
}
}
// xvalues returns the value of a byte as a hexadecimal digit or 255.
var xvalues = [256]byte{
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
}
// xtob converts hex characters x1 and x2 into a byte.
func xtob(x1, x2 byte) (byte, bool) {
b1 := xvalues[x1]
b2 := xvalues[x2]
return (b1 << 4) | b2, b1 != 255 && b2 != 255
}

245
vendor/github.com/google/uuid/uuid.go generated vendored Normal file
View File

@ -0,0 +1,245 @@
// Copyright 2018 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"bytes"
"crypto/rand"
"encoding/hex"
"errors"
"fmt"
"io"
"strings"
)
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
// 4122.
type UUID [16]byte
// A Version represents a UUID's version.
type Version byte
// A Variant represents a UUID's variant.
type Variant byte
// Constants returned by Variant.
const (
Invalid = Variant(iota) // Invalid UUID
RFC4122 // The variant specified in RFC4122
Reserved // Reserved, NCS backward compatibility.
Microsoft // Reserved, Microsoft Corporation backward compatibility.
Future // Reserved for future definition.
)
var rander = rand.Reader // random function
// Parse decodes s into a UUID or returns an error. Both the standard UUID
// forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded as well as the
// Microsoft encoding {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} and the raw hex
// encoding: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
func Parse(s string) (UUID, error) {
var uuid UUID
switch len(s) {
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
case 36:
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
case 36 + 9:
if strings.ToLower(s[:9]) != "urn:uuid:" {
return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9])
}
s = s[9:]
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
case 36 + 2:
s = s[1:]
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
case 32:
var ok bool
for i := range uuid {
uuid[i], ok = xtob(s[i*2], s[i*2+1])
if !ok {
return uuid, errors.New("invalid UUID format")
}
}
return uuid, nil
default:
return uuid, fmt.Errorf("invalid UUID length: %d", len(s))
}
// s is now at least 36 bytes long
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
return uuid, errors.New("invalid UUID format")
}
for i, x := range [16]int{
0, 2, 4, 6,
9, 11,
14, 16,
19, 21,
24, 26, 28, 30, 32, 34} {
v, ok := xtob(s[x], s[x+1])
if !ok {
return uuid, errors.New("invalid UUID format")
}
uuid[i] = v
}
return uuid, nil
}
// ParseBytes is like Parse, except it parses a byte slice instead of a string.
func ParseBytes(b []byte) (UUID, error) {
var uuid UUID
switch len(b) {
case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
if !bytes.Equal(bytes.ToLower(b[:9]), []byte("urn:uuid:")) {
return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9])
}
b = b[9:]
case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
b = b[1:]
case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
var ok bool
for i := 0; i < 32; i += 2 {
uuid[i/2], ok = xtob(b[i], b[i+1])
if !ok {
return uuid, errors.New("invalid UUID format")
}
}
return uuid, nil
default:
return uuid, fmt.Errorf("invalid UUID length: %d", len(b))
}
// s is now at least 36 bytes long
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' {
return uuid, errors.New("invalid UUID format")
}
for i, x := range [16]int{
0, 2, 4, 6,
9, 11,
14, 16,
19, 21,
24, 26, 28, 30, 32, 34} {
v, ok := xtob(b[x], b[x+1])
if !ok {
return uuid, errors.New("invalid UUID format")
}
uuid[i] = v
}
return uuid, nil
}
// MustParse is like Parse but panics if the string cannot be parsed.
// It simplifies safe initialization of global variables holding compiled UUIDs.
func MustParse(s string) UUID {
uuid, err := Parse(s)
if err != nil {
panic(`uuid: Parse(` + s + `): ` + err.Error())
}
return uuid
}
// FromBytes creates a new UUID from a byte slice. Returns an error if the slice
// does not have a length of 16. The bytes are copied from the slice.
func FromBytes(b []byte) (uuid UUID, err error) {
err = uuid.UnmarshalBinary(b)
return uuid, err
}
// Must returns uuid if err is nil and panics otherwise.
func Must(uuid UUID, err error) UUID {
if err != nil {
panic(err)
}
return uuid
}
// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
// , or "" if uuid is invalid.
func (uuid UUID) String() string {
var buf [36]byte
encodeHex(buf[:], uuid)
return string(buf[:])
}
// URN returns the RFC 2141 URN form of uuid,
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid.
func (uuid UUID) URN() string {
var buf [36 + 9]byte
copy(buf[:], "urn:uuid:")
encodeHex(buf[9:], uuid)
return string(buf[:])
}
func encodeHex(dst []byte, uuid UUID) {
hex.Encode(dst, uuid[:4])
dst[8] = '-'
hex.Encode(dst[9:13], uuid[4:6])
dst[13] = '-'
hex.Encode(dst[14:18], uuid[6:8])
dst[18] = '-'
hex.Encode(dst[19:23], uuid[8:10])
dst[23] = '-'
hex.Encode(dst[24:], uuid[10:])
}
// Variant returns the variant encoded in uuid.
func (uuid UUID) Variant() Variant {
switch {
case (uuid[8] & 0xc0) == 0x80:
return RFC4122
case (uuid[8] & 0xe0) == 0xc0:
return Microsoft
case (uuid[8] & 0xe0) == 0xe0:
return Future
default:
return Reserved
}
}
// Version returns the version of uuid.
func (uuid UUID) Version() Version {
return Version(uuid[6] >> 4)
}
func (v Version) String() string {
if v > 15 {
return fmt.Sprintf("BAD_VERSION_%d", v)
}
return fmt.Sprintf("VERSION_%d", v)
}
func (v Variant) String() string {
switch v {
case RFC4122:
return "RFC4122"
case Reserved:
return "Reserved"
case Microsoft:
return "Microsoft"
case Future:
return "Future"
case Invalid:
return "Invalid"
}
return fmt.Sprintf("BadVariant%d", int(v))
}
// SetRand sets the random number generator to r, which implements io.Reader.
// If r.Read returns an error when the package requests random data then
// a panic will be issued.
//
// Calling SetRand with nil sets the random number generator to the default
// generator.
func SetRand(r io.Reader) {
if r == nil {
rander = rand.Reader
return
}
rander = r
}

44
vendor/github.com/google/uuid/version1.go generated vendored Normal file
View File

@ -0,0 +1,44 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import (
"encoding/binary"
)
// NewUUID returns a Version 1 UUID based on the current NodeID and clock
// sequence, and the current time. If the NodeID has not been set by SetNodeID
// or SetNodeInterface then it will be set automatically. If the NodeID cannot
// be set NewUUID returns nil. If clock sequence has not been set by
// SetClockSequence then it will be set automatically. If GetTime fails to
// return the current NewUUID returns nil and an error.
//
// In most cases, New should be used.
func NewUUID() (UUID, error) {
nodeMu.Lock()
if nodeID == zeroID {
setNodeInterface("")
}
nodeMu.Unlock()
var uuid UUID
now, seq, err := GetTime()
if err != nil {
return uuid, err
}
timeLow := uint32(now & 0xffffffff)
timeMid := uint16((now >> 32) & 0xffff)
timeHi := uint16((now >> 48) & 0x0fff)
timeHi |= 0x1000 // Version 1
binary.BigEndian.PutUint32(uuid[0:], timeLow)
binary.BigEndian.PutUint16(uuid[4:], timeMid)
binary.BigEndian.PutUint16(uuid[6:], timeHi)
binary.BigEndian.PutUint16(uuid[8:], seq)
copy(uuid[10:], nodeID[:])
return uuid, nil
}

38
vendor/github.com/google/uuid/version4.go generated vendored Normal file
View File

@ -0,0 +1,38 @@
// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package uuid
import "io"
// New creates a new random UUID or panics. New is equivalent to
// the expression
//
// uuid.Must(uuid.NewRandom())
func New() UUID {
return Must(NewRandom())
}
// NewRandom returns a Random (Version 4) UUID.
//
// The strength of the UUIDs is based on the strength of the crypto/rand
// package.
//
// A note about uniqueness derived from the UUID Wikipedia entry:
//
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
// hit by a meteorite is estimated to be one chance in 17 billion, that
// means the probability is about 0.00000000006 (6 × 1011),
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
// year and having one duplicate.
func NewRandom() (UUID, error) {
var uuid UUID
_, err := io.ReadFull(rander, uuid[:])
if err != nil {
return Nil, err
}
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
return uuid, nil
}

View File

@ -0,0 +1,9 @@
(The MIT License)
Copyright (c) 2017 marvin + konsorten GmbH (open-source@konsorten.de)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,41 @@
# Windows Terminal Sequences
This library allow for enabling Windows terminal color support for Go.
See [Console Virtual Terminal Sequences](https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences) for details.
## Usage
```go
import (
"syscall"
sequences "github.com/konsorten/go-windows-terminal-sequences"
)
func main() {
sequences.EnableVirtualTerminalProcessing(syscall.Stdout, true)
}
```
## Authors
The tool is sponsored by the [marvin + konsorten GmbH](http://www.konsorten.de).
We thank all the authors who provided code to this library:
* Felix Kollmann
* Nicolas Perraut
## License
(The MIT License)
Copyright (c) 2018 marvin + konsorten GmbH (open-source@konsorten.de)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1 @@
module github.com/konsorten/go-windows-terminal-sequences

View File

@ -0,0 +1,36 @@
// +build windows
package sequences
import (
"syscall"
"unsafe"
)
var (
kernel32Dll *syscall.LazyDLL = syscall.NewLazyDLL("Kernel32.dll")
setConsoleMode *syscall.LazyProc = kernel32Dll.NewProc("SetConsoleMode")
)
func EnableVirtualTerminalProcessing(stream syscall.Handle, enable bool) error {
const ENABLE_VIRTUAL_TERMINAL_PROCESSING uint32 = 0x4
var mode uint32
err := syscall.GetConsoleMode(syscall.Stdout, &mode)
if err != nil {
return err
}
if enable {
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING
} else {
mode &^= ENABLE_VIRTUAL_TERMINAL_PROCESSING
}
ret, _, err := setConsoleMode.Call(uintptr(unsafe.Pointer(stream)), uintptr(mode))
if ret == 0 {
return err
}
return nil
}

View File

@ -0,0 +1,11 @@
// +build linux darwin
package sequences
import (
"fmt"
)
func EnableVirtualTerminalProcessing(stream uintptr, enable bool) error {
return fmt.Errorf("windows only package")
}

2
vendor/github.com/mattn/goveralls/.gitignore generated vendored Normal file
View File

@ -0,0 +1,2 @@
*~
/goveralls

14
vendor/github.com/mattn/goveralls/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,14 @@
language: go
go:
- '1.7'
- '1.8'
- '1.9'
- '1.10'
- '1.11'
- '1.12'
- '1.13'
before_install:
- go get ./...
- go install .
script:
- goveralls

266
vendor/github.com/mattn/goveralls/README.md generated vendored Normal file
View File

@ -0,0 +1,266 @@
goveralls
=========
[Go](http://golang.org) integration for [Coveralls.io](http://coveralls.io)
continuous code coverage tracking system.
# Installation
`goveralls` requires a working Go installation (Go-1.2 or higher).
```bash
$ go get github.com/mattn/goveralls
```
# Usage
First you will need an API token. It is found at the bottom of your
repository's page when you are logged in to Coveralls.io. Each repo has its
own token.
```bash
$ cd $GOPATH/src/github.com/yourusername/yourpackage
$ goveralls -repotoken your_repos_coveralls_token
```
You can set the environment variable `$COVERALLS_TOKEN` to your token so you do
not have to specify it at each invocation.
You can also run this reporter for multiple passes with the flag `-parallel` or
by setting the environment variable `COVERALLS_PARALLEL=true` (see [coveralls
docs](https://docs.coveralls.io/parallel-build-webhook) for more details.
# Continuous Integration
There is no need to run `go test` separately, as `goveralls` runs the entire
test suite.
## Github Actions
[shogo82148/actions-goveralls](https://github.com/marketplace/actions/actions-goveralls) is available on GitHub Marketplace.
It provides the shorthand of the GitHub Actions YAML configure.
```yaml
name: Quality
on: [push, pull_request]
jobs:
test:
name: Test with Coverage
runs-on: ubuntu-latest
steps:
- name: Set up Go
uses: actions/setup-go@v1
with:
go-version: '1.13'
- name: Check out code
uses: actions/checkout@v2
- name: Install dependencies
run: |
go mod download
- name: Run Unit tests
run: |
go test -race -covermode atomic -coverprofile=profile.cov ./...
- name: Send coverage
env:
COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
GO111MODULE=off go get github.com/mattn/goveralls
$(go env GOPATH)/bin/goveralls -coverprofile=profile.cov -service=github
# or use shogo82148/actions-goveralls
# - name: Send coverage
# uses: shogo82148/actions-goveralls@v1
# with:
# path-to-profile: profile.cov
```
### Test with Legacy GOPATH mode
If you want to use Go 1.10 or earlier, you have to set `GOPATH` environment value and the working directory.
See <https://github.com/golang/go/wiki/GOPATH> for more detail.
Here is an example for testing `example.com/owner/repo` package.
```yaml
name: Quality
on: [push, pull_request]
jobs:
test:
name: Test with Coverage
runs-on: ubuntu-latest
steps:
- name: Set up Go
uses: actions/setup-go@v1
with:
go-version: '1.10'
# add this step
- name: Set up GOPATH
run: |
echo "::set-env name=GOPATH::${{ github.workspace }}"
echo "::add-path::${{ github.workspace }}/bin"
- name: Check out code
uses: actions/checkout@v2
with:
path: src/example.com/owner/repo # add this
- name: Run Unit tests
run: |
go test -race -covermode atomic -coverprofile=profile.cov ./...
working-directory: src/example.com/owner/repo # add this
- name: Send coverage
env:
COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
GO111MODULE=off go get github.com/mattn/goveralls
$(go env GOPATH)/bin/goveralls -coverprofile=profile.cov -service=github
working-directory: src/example.com/owner/repo # add this
```
## Travis CI
### GitHub Integration
Enable Travis-CI on your github repository settings.
For a **public** github repository put bellow's `.travis.yml`.
```yml
language: go
go:
- tip
before_install:
- go get github.com/mattn/goveralls
script:
- $GOPATH/bin/goveralls -service=travis-ci
```
For a **public** github repository, it is not necessary to define your repository key (`COVERALLS_TOKEN`).
For a **private** github repository put bellow's `.travis.yml`. If you use **travis pro**, you need to specify `-service=travis-pro` instead of `-service=travis-ci`.
```yml
language: go
go:
- tip
before_install:
- go get github.com/mattn/goveralls
script:
- $GOPATH/bin/goveralls -service=travis-pro
```
Store your Coveralls API token in `Environment variables`.
```
COVERALLS_TOKEN = your_token_goes_here
```
or you can store token using [travis encryption keys](https://docs.travis-ci.com/user/encryption-keys/). Note that this is the token provided in the page for that specific repository on Coveralls. This is *not* one that was created from the "Personal API Tokens" area under your Coveralls account settings.
```
$ gem install travis
$ travis encrypt COVERALLS_TOKEN=your_token_goes_here --add env.global
```
travis will add `env` block as following example:
```yml
env:
global:
secure: xxxxxxxxxxxxx
```
### For others:
```
$ go get github.com/mattn/goveralls
$ go test -covermode=count -coverprofile=profile.cov
$ goveralls -coverprofile=profile.cov -service=travis-ci
```
## Drone.io
Store your Coveralls API token in `Environment Variables`:
```
COVERALLS_TOKEN=your_token_goes_here
```
Replace the `go test` line in your `Commands` with these lines:
```
$ go get github.com/mattn/goveralls
$ goveralls -service drone.io
```
`goveralls` automatically use the environment variable `COVERALLS_TOKEN` as the
default value for `-repotoken`.
You can use the `-v` flag to see verbose output from the test suite:
```
$ goveralls -v -service drone.io
```
## CircleCI
Store your Coveralls API token as an [Environment Variable](https://circleci.com/docs/environment-variables).
In your `circle.yml` add the following commands under the `test` section.
```yml
test:
pre:
- go get github.com/mattn/goveralls
override:
- go test -v -cover -race -coverprofile=/home/ubuntu/coverage.out
post:
- /home/ubuntu/.go_workspace/bin/goveralls -coverprofile=/home/ubuntu/coverage.out -service=circle-ci -repotoken=$COVERALLS_TOKEN
```
For more information, See https://coveralls.zendesk.com/hc/en-us/articles/201342809-Go
## Semaphore
Store your Coveralls API token in `Environment Variables`:
```
COVERALLS_TOKEN=your_token_goes_here
```
More instructions on how to do this can be found in the [Semaphore documentation](https://semaphoreci.com/docs/exporting-environment-variables.html).
Replace the `go test` line in your `Commands` with these lines:
```
$ go get github.com/mattn/goveralls
$ goveralls -service semaphore
```
`goveralls` automatically use the environment variable `COVERALLS_TOKEN` as the
default value for `-repotoken`.
You can use the `-v` flag to see verbose output from the test suite:
```
$ goveralls -v -service semaphore
```
## Coveralls Enterprise
If you are using Coveralls Enterprise and have a self-signed certificate, you need to skip certificate verification:
```shell
$ goveralls -insecure
```
# Authors
* Yasuhiro Matsumoto (a.k.a. mattn)
* haya14busa
# License
under the MIT License: http://mattn.mit-license.org/2016

124
vendor/github.com/mattn/goveralls/gitinfo.go generated vendored Normal file
View File

@ -0,0 +1,124 @@
package main
import (
"bytes"
"log"
"os"
"os/exec"
"strings"
)
// A Head object encapsulates information about the HEAD revision of a git repo.
type Head struct {
ID string `json:"id"`
AuthorName string `json:"author_name,omitempty"`
AuthorEmail string `json:"author_email,omitempty"`
CommitterName string `json:"committer_name,omitempty"`
CommitterEmail string `json:"committer_email,omitempty"`
Message string `json:"message"`
}
// A Git object encapsulates information about a git repo.
type Git struct {
Head Head `json:"head"`
Branch string `json:"branch"`
}
// collectGitInfo runs several git commands to compose a Git object.
func collectGitInfo(ref string) *Git {
gitCmds := map[string][]string{
"id": {"rev-parse", ref},
"branch": {"branch", "--format", "%(refname:short)", "--contains", ref},
"aname": {"show", "-s", "--format=%aN", ref},
"aemail": {"show", "-s", "--format=%aE", ref},
"cname": {"show", "-s", "--format=%cN", ref},
"cemail": {"show", "-s", "--format=%cE", ref},
"message": {"show", "-s", "--format=%s", ref},
}
results := map[string]string{}
gitPath, err := exec.LookPath("git")
if err != nil {
log.Printf("fail to look path of git: %v", err)
log.Print("git information is omitted")
return nil
}
if ref != "HEAD" {
// make sure that the commit is in the local
// e.g. shallow cloned repository
_, _ = runCommand(gitPath, "fetch", "--depth=1", "origin", ref)
// ignore errors because we don't have enough information about the origin.
}
for key, args := range gitCmds {
if key == "branch" {
if envBranch := loadBranchFromEnv(); envBranch != "" {
results[key] = envBranch
continue
}
}
ret, err := runCommand(gitPath, args...)
if err != nil {
log.Printf(`fail to run "%s %s": %v`, gitPath, strings.Join(args, " "), err)
log.Print("git information is omitted")
return nil
}
results[key] = ret
}
h := Head{
ID: firstLine(results["id"]),
AuthorName: firstLine(results["aname"]),
AuthorEmail: firstLine(results["aemail"]),
CommitterName: firstLine(results["cname"]),
CommitterEmail: firstLine(results["cemail"]),
Message: results["message"],
}
g := &Git{
Head: h,
Branch: firstLine(results["branch"]),
}
return g
}
func runCommand(gitPath string, args ...string) (string, error) {
cmd := exec.Command(gitPath, args...)
ret, err := cmd.CombinedOutput()
if err != nil {
return "", err
}
ret = bytes.TrimRight(ret, "\n")
return string(ret), nil
}
func firstLine(s string) string {
if idx := strings.Index(s, "\n"); idx >= 0 {
return s[:idx]
}
return s
}
var varNames = [...]string{
"GIT_BRANCH",
// https://help.github.com/en/actions/automating-your-workflow-with-github-actions/using-environment-variables
"GITHUB_HEAD_REF", "GITHUB_REF",
"CIRCLE_BRANCH", "TRAVIS_BRANCH",
"CI_BRANCH", "APPVEYOR_REPO_BRANCH",
"WERCKER_GIT_BRANCH", "DRONE_BRANCH",
"BUILDKITE_BRANCH", "BRANCH_NAME",
}
func loadBranchFromEnv() string {
for _, varName := range varNames {
if branch := os.Getenv(varName); branch != "" {
if varName == "GITHUB_REF" {
return strings.TrimPrefix(branch, "refs/heads/")
}
return branch
}
}
return ""
}

5
vendor/github.com/mattn/goveralls/go.mod generated vendored Normal file
View File

@ -0,0 +1,5 @@
module github.com/mattn/goveralls
go 1.11
require golang.org/x/tools v0.0.0-20200113040837-eac381796e91

17
vendor/github.com/mattn/goveralls/go.sum generated vendored Normal file
View File

@ -0,0 +1,17 @@
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20191118222007-07fc4c7f2b98 h1:tZwpOHmF1OEL9wJGSgBALnhFg/8VKjQTtctCX51GLNI=
golang.org/x/tools v0.0.0-20191118222007-07fc4c7f2b98/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200110213125-a7a6caa82ab2 h1:V9r/14uGBqLgNlHRYWdVqjMdWkcOHnE2KG8DwVqQSEc=
golang.org/x/tools v0.0.0-20200110213125-a7a6caa82ab2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200113040837-eac381796e91 h1:OOkytthzFBKHY5EfEgLUabprb0LtJVkQtNxAQ02+UE4=
golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

131
vendor/github.com/mattn/goveralls/gocover.go generated vendored Normal file
View File

@ -0,0 +1,131 @@
package main
// Much of the core of this is copied from go's cover tool itself.
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// The rest is written by Dustin Sallings
import (
"bytes"
"fmt"
"go/build"
"io/ioutil"
"log"
"path/filepath"
"strings"
"golang.org/x/tools/cover"
)
func findFile(file string) (string, error) {
dir, file := filepath.Split(file)
pkg, err := build.Import(dir, ".", build.FindOnly)
if err != nil {
return "", fmt.Errorf("can't find %q: %v", file, err)
}
return filepath.Join(pkg.Dir, file), nil
}
// mergeProfs merges profiles for same target packages.
// It assumes each profiles have same sorted FileName and Blocks.
func mergeProfs(pfss [][]*cover.Profile) []*cover.Profile {
// skip empty profiles ([no test files])
for i := 0; i < len(pfss); i++ {
if len(pfss[i]) > 0 {
pfss = pfss[i:]
break
}
}
if len(pfss) == 0 {
return nil
} else if len(pfss) == 1 {
return pfss[0]
}
head, rest := pfss[0], pfss[1:]
ret := make([]*cover.Profile, 0, len(head))
for i, profile := range head {
for _, ps := range rest {
// find profiles
if len(ps) == 0 {
continue
} else if len(ps) < i+1 {
continue
} else if ps[i].FileName != profile.FileName {
continue
}
profile.Blocks = mergeProfBlocks(profile.Blocks, ps[i].Blocks)
}
ret = append(ret, profile)
}
return ret
}
func mergeProfBlocks(as, bs []cover.ProfileBlock) []cover.ProfileBlock {
if len(as) != len(bs) {
log.Fatal("Two block length should be same")
}
// cover.ProfileBlock generated by cover.ParseProfiles() is sorted by
// StartLine and StartCol, so we can use index.
ret := make([]cover.ProfileBlock, 0, len(as))
for i, a := range as {
b := bs[i]
if a.StartLine != b.StartLine || a.StartCol != b.StartCol {
log.Fatal("Blocks are not sorted")
}
a.Count += b.Count
ret = append(ret, a)
}
return ret
}
// toSF converts profiles to sourcefiles for coveralls.
func toSF(profs []*cover.Profile) ([]*SourceFile, error) {
var rv []*SourceFile
for _, prof := range profs {
path, err := findFile(prof.FileName)
if err != nil {
log.Fatalf("Can't find %v", err)
}
fb, err := ioutil.ReadFile(path)
if err != nil {
log.Fatalf("Error reading %v: %v", path, err)
}
sf := &SourceFile{
Name: getCoverallsSourceFileName(path),
Source: string(fb),
Coverage: make([]interface{}, 1+bytes.Count(fb, []byte{'\n'})),
}
for _, block := range prof.Blocks {
for i := block.StartLine; i <= block.EndLine; i++ {
count, _ := sf.Coverage[i-1].(int)
sf.Coverage[i-1] = count + block.Count
}
}
rv = append(rv, sf)
}
return rv, nil
}
func parseCover(fn string) ([]*SourceFile, error) {
var pfss [][]*cover.Profile
for _, p := range strings.Split(fn, ",") {
profs, err := cover.ParseProfiles(p)
if err != nil {
return nil, fmt.Errorf("Error parsing coverage: %v", err)
}
pfss = append(pfss, profs)
}
sourceFiles, err := toSF(mergeProfs(pfss))
if err != nil {
return nil, err
}
return sourceFiles, nil
}

508
vendor/github.com/mattn/goveralls/goveralls.go generated vendored Normal file
View File

@ -0,0 +1,508 @@
// Copyright (c) 2013 Yasuhiro Matsumoto, Jason McVetta.
// This is Free Software, released under the MIT license.
// See http://mattn.mit-license.org/2013 for details.
// goveralls is a Go client for Coveralls.io.
package main
import (
"bytes"
_ "crypto/sha512"
"crypto/tls"
"encoding/json"
"errors"
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"os/exec"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
"golang.org/x/tools/cover"
)
/*
https://coveralls.io/docs/api_reference
*/
// Flags are extra flags to the tests
type Flags []string
// String implements flag.Value interface.
func (a *Flags) String() string {
return strings.Join(*a, ",")
}
// Set implements flag.Value interface.
func (a *Flags) Set(value string) error {
*a = append(*a, value)
return nil
}
var (
extraFlags Flags
pkg = flag.String("package", "", "Go package")
verbose = flag.Bool("v", false, "Pass '-v' argument to 'go test' and output to stdout")
race = flag.Bool("race", false, "Pass '-race' argument to 'go test'")
debug = flag.Bool("debug", false, "Enable debug output")
coverprof = flag.String("coverprofile", "", "If supplied, use a go cover profile (comma separated)")
covermode = flag.String("covermode", "count", "sent as covermode argument to go test")
repotoken = flag.String("repotoken", os.Getenv("COVERALLS_TOKEN"), "Repository Token on coveralls")
reponame = flag.String("reponame", "", "Repository name")
parallel = flag.Bool("parallel", os.Getenv("COVERALLS_PARALLEL") != "", "Submit as parallel")
endpoint = flag.String("endpoint", "https://coveralls.io", "Hostname to submit Coveralls data to")
service = flag.String("service", "", "The CI service or other environment in which the test suite was run. ")
shallow = flag.Bool("shallow", false, "Shallow coveralls internal server errors")
ignore = flag.String("ignore", "", "Comma separated files to ignore")
insecure = flag.Bool("insecure", false, "Set insecure to skip verification of certificates")
show = flag.Bool("show", false, "Show which package is being tested")
customJobID = flag.String("jobid", "", "Custom set job token")
jobNumber = flag.String("jobnumber", "", "Custom set job number")
parallelFinish = flag.Bool("parallel-finish", false, "finish parallel test")
)
// usage supplants package flag's Usage variable
var usage = func() {
cmd := os.Args[0]
// fmt.Fprintf(os.Stderr, "Usage of %s:\n", cmd)
s := "Usage: %s [options]\n"
fmt.Fprintf(os.Stderr, s, cmd)
flag.PrintDefaults()
}
// A SourceFile represents a source code file and its coverage data for a
// single job.
type SourceFile struct {
Name string `json:"name"` // File path of this source file
Source string `json:"source"` // Full source code of this file
Coverage []interface{} `json:"coverage"` // Requires both nulls and integers
}
// A Job represents the coverage data from a single run of a test suite.
type Job struct {
RepoToken *string `json:"repo_token,omitempty"`
ServiceJobID string `json:"service_job_id"`
ServiceJobNumber string `json:"service_job_number,omitempty"`
ServicePullRequest string `json:"service_pull_request,omitempty"`
ServiceName string `json:"service_name"`
SourceFiles []*SourceFile `json:"source_files"`
Parallel *bool `json:"parallel,omitempty"`
Git *Git `json:"git,omitempty"`
RunAt time.Time `json:"run_at"`
}
// A Response is returned by the Coveralls.io API.
type Response struct {
Message string `json:"message"`
URL string `json:"url"`
Error bool `json:"error"`
}
// A WebHookResponse is returned by the Coveralls.io WebHook.
type WebHookResponse struct {
Done bool `json:"done"`
}
// getPkgs returns packages for measuring coverage. Returned packages doesn't
// contain vendor packages.
func getPkgs(pkg string) ([]string, error) {
if pkg == "" {
pkg = "./..."
}
out, err := exec.Command("go", "list", pkg).CombinedOutput()
if err != nil {
return nil, err
}
allPkgs := strings.Split(strings.Trim(string(out), "\n"), "\n")
pkgs := make([]string, 0, len(allPkgs))
for _, p := range allPkgs {
if strings.Contains(p, "/vendor/") {
continue
}
// go modules output
if strings.Contains(p, "go: ") {
continue
}
pkgs = append(pkgs, p)
}
return pkgs, nil
}
func getCoverage() ([]*SourceFile, error) {
if *coverprof != "" {
return parseCover(*coverprof)
}
// pkgs is packages to run tests and get coverage.
pkgs, err := getPkgs(*pkg)
if err != nil {
return nil, err
}
coverpkg := fmt.Sprintf("-coverpkg=%s", strings.Join(pkgs, ","))
var pfss [][]*cover.Profile
for _, line := range pkgs {
f, err := ioutil.TempFile("", "goveralls")
if err != nil {
return nil, err
}
f.Close()
cmd := exec.Command("go")
outBuf := new(bytes.Buffer)
cmd.Stdout = outBuf
cmd.Stderr = outBuf
coverm := *covermode
if *race {
coverm = "atomic"
}
args := []string{"go", "test", "-covermode", coverm, "-coverprofile", f.Name(), coverpkg}
if *verbose {
args = append(args, "-v")
cmd.Stdout = os.Stdout
}
if *race {
args = append(args, "-race")
}
args = append(args, extraFlags...)
args = append(args, line)
cmd.Args = args
if *show {
fmt.Println("goveralls:", line)
}
err = cmd.Run()
if err != nil {
return nil, fmt.Errorf("%v: %v", err, outBuf.String())
}
pfs, err := cover.ParseProfiles(f.Name())
if err != nil {
return nil, err
}
err = os.Remove(f.Name())
if err != nil {
return nil, err
}
pfss = append(pfss, pfs)
}
sourceFiles, err := toSF(mergeProfs(pfss))
if err != nil {
return nil, err
}
return sourceFiles, nil
}
var vscDirs = []string{".git", ".hg", ".bzr", ".svn"}
func findRepositoryRoot(dir string) (string, bool) {
for _, vcsdir := range vscDirs {
if d, err := os.Stat(filepath.Join(dir, vcsdir)); err == nil && d.IsDir() {
return dir, true
}
}
nextdir := filepath.Dir(dir)
if nextdir == dir {
return "", false
}
return findRepositoryRoot(nextdir)
}
func getCoverallsSourceFileName(name string) string {
if dir, ok := findRepositoryRoot(name); ok {
name = strings.TrimPrefix(name, dir+string(os.PathSeparator))
}
return filepath.ToSlash(name)
}
// processParallelFinish notifies coveralls that all jobs are completed
// ref. https://docs.coveralls.io/parallel-build-webhook
func processParallelFinish(jobID, token string) error {
var name string
if reponame != nil && *reponame != "" {
name = *reponame
} else if s := os.Getenv("GITHUB_REPOSITORY"); s != "" {
name = s
}
params := make(url.Values)
params.Set("repo_token", token)
params.Set("repo_name", name)
params.Set("payload[build_num]", jobID)
params.Set("payload[status]", "done")
res, err := http.PostForm(*endpoint+"/webhook", params)
if err != nil {
return err
}
defer res.Body.Close()
bodyBytes, err := ioutil.ReadAll(res.Body)
if err != nil {
return fmt.Errorf("Unable to read response body from coveralls: %s", err)
}
if res.StatusCode >= http.StatusInternalServerError && *shallow {
fmt.Println("coveralls server failed internally")
return nil
}
if res.StatusCode != 200 {
return fmt.Errorf("Bad response status from coveralls: %d\n%s", res.StatusCode, bodyBytes)
}
var response WebHookResponse
if err = json.Unmarshal(bodyBytes, &response); err != nil {
return fmt.Errorf("Unable to unmarshal response JSON from coveralls: %s\n%s", err, bodyBytes)
}
if !response.Done {
return fmt.Errorf("jobs are not completed:\n%s", bodyBytes)
}
return nil
}
func process() error {
log.SetFlags(log.Ltime | log.Lshortfile)
//
// Parse Flags
//
flag.Usage = usage
flag.Var(&extraFlags, "flags", "extra flags to the tests")
flag.Parse()
if len(flag.Args()) > 0 {
flag.Usage()
os.Exit(1)
}
//
// Setup PATH environment variable
//
paths := filepath.SplitList(os.Getenv("PATH"))
if goroot := os.Getenv("GOROOT"); goroot != "" {
paths = append(paths, filepath.Join(goroot, "bin"))
}
if gopath := os.Getenv("GOPATH"); gopath != "" {
for _, path := range filepath.SplitList(gopath) {
paths = append(paths, filepath.Join(path, "bin"))
}
}
os.Setenv("PATH", strings.Join(paths, string(filepath.ListSeparator)))
//
// Handle certificate verification configuration
//
if *insecure {
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
}
//
// Initialize Job
//
// flags are never nil, so no nil check needed
githubEvent := getGithubEvent()
var jobID string
if *customJobID != "" {
jobID = *customJobID
} else if ServiceJobID := os.Getenv("COVERALLS_SERVICE_JOB_ID"); ServiceJobID != "" {
jobID = ServiceJobID
} else if travisjobID := os.Getenv("TRAVIS_JOB_ID"); travisjobID != "" {
jobID = travisjobID
} else if circleCIJobID := os.Getenv("CIRCLE_BUILD_NUM"); circleCIJobID != "" {
jobID = circleCIJobID
} else if appveyorJobID := os.Getenv("APPVEYOR_JOB_ID"); appveyorJobID != "" {
jobID = appveyorJobID
} else if semaphorejobID := os.Getenv("SEMAPHORE_BUILD_NUMBER"); semaphorejobID != "" {
jobID = semaphorejobID
} else if jenkinsjobID := os.Getenv("BUILD_NUMBER"); jenkinsjobID != "" {
jobID = jenkinsjobID
} else if buildID := os.Getenv("BUILDKITE_BUILD_ID"); buildID != "" {
jobID = buildID
} else if droneBuildNumber := os.Getenv("DRONE_BUILD_NUMBER"); droneBuildNumber != "" {
jobID = droneBuildNumber
} else if buildkiteBuildNumber := os.Getenv("BUILDKITE_BUILD_NUMBER"); buildkiteBuildNumber != "" {
jobID = buildkiteBuildNumber
} else if codeshipjobID := os.Getenv("CI_BUILD_ID"); codeshipjobID != "" {
jobID = codeshipjobID
} else if githubSHA := os.Getenv("GITHUB_SHA"); githubSHA != "" {
githubShortSha := githubSHA[0:9]
if os.Getenv("GITHUB_EVENT_NAME") == "pull_request" {
number := githubEvent["number"].(float64)
jobID = fmt.Sprintf(`%s-PR-%d`, githubShortSha, int(number))
} else {
jobID = githubShortSha
}
}
if *parallelFinish {
return processParallelFinish(jobID, *repotoken)
}
if *repotoken == "" {
repotoken = nil // remove the entry from json
}
head := "HEAD"
var pullRequest string
if prNumber := os.Getenv("CIRCLE_PR_NUMBER"); prNumber != "" {
// for Circle CI (pull request from forked repo)
pullRequest = prNumber
} else if prNumber := os.Getenv("TRAVIS_PULL_REQUEST"); prNumber != "" && prNumber != "false" {
pullRequest = prNumber
} else if prURL := os.Getenv("CI_PULL_REQUEST"); prURL != "" {
// for Circle CI
pullRequest = regexp.MustCompile(`[0-9]+$`).FindString(prURL)
} else if prNumber := os.Getenv("APPVEYOR_PULL_REQUEST_NUMBER"); prNumber != "" {
pullRequest = prNumber
} else if prNumber := os.Getenv("PULL_REQUEST_NUMBER"); prNumber != "" {
pullRequest = prNumber
} else if prNumber := os.Getenv("BUILDKITE_PULL_REQUEST"); prNumber != "" {
pullRequest = prNumber
} else if prNumber := os.Getenv("DRONE_PULL_REQUEST"); prNumber != "" {
pullRequest = prNumber
} else if prNumber := os.Getenv("BUILDKITE_PULL_REQUEST"); prNumber != "" {
pullRequest = prNumber
} else if prNumber := os.Getenv("CI_PR_NUMBER"); prNumber != "" {
pullRequest = prNumber
} else if os.Getenv("GITHUB_EVENT_NAME") == "pull_request" {
number := githubEvent["number"].(float64)
pullRequest = strconv.Itoa(int(number))
ghPR := githubEvent["pull_request"].(map[string]interface{})
ghHead := ghPR["head"].(map[string]interface{})
head = ghHead["sha"].(string)
}
if *service == "" && os.Getenv("TRAVIS_JOB_ID") != "" {
*service = "travis-ci"
}
sourceFiles, err := getCoverage()
if err != nil {
return err
}
j := Job{
RunAt: time.Now(),
RepoToken: repotoken,
ServicePullRequest: pullRequest,
Parallel: parallel,
Git: collectGitInfo(head),
SourceFiles: sourceFiles,
ServiceName: *service,
}
// Only include a job ID if it's known, otherwise, Coveralls looks
// for the job and can't find it.
if jobID != "" {
j.ServiceJobID = jobID
}
j.ServiceJobNumber = *jobNumber
// Ignore files
if len(*ignore) > 0 {
patterns := strings.Split(*ignore, ",")
for i, pattern := range patterns {
patterns[i] = strings.TrimSpace(pattern)
}
var files []*SourceFile
Files:
for _, file := range j.SourceFiles {
for _, pattern := range patterns {
match, err := filepath.Match(pattern, file.Name)
if err != nil {
return err
}
if match {
fmt.Printf("ignoring %s\n", file.Name)
continue Files
}
}
files = append(files, file)
}
j.SourceFiles = files
}
if *debug {
b, err := json.MarshalIndent(j, "", " ")
if err != nil {
return err
}
log.Printf("Posting data: %s", b)
}
b, err := json.Marshal(j)
if err != nil {
return err
}
params := make(url.Values)
params.Set("json", string(b))
res, err := http.PostForm(*endpoint+"/api/v1/jobs", params)
if err != nil {
return err
}
defer res.Body.Close()
bodyBytes, err := ioutil.ReadAll(res.Body)
if err != nil {
return fmt.Errorf("Unable to read response body from coveralls: %s", err)
}
if res.StatusCode >= http.StatusInternalServerError && *shallow {
fmt.Println("coveralls server failed internally")
return nil
}
if res.StatusCode != 200 {
return fmt.Errorf("Bad response status from coveralls: %d\n%s", res.StatusCode, bodyBytes)
}
var response Response
if err = json.Unmarshal(bodyBytes, &response); err != nil {
return fmt.Errorf("Unable to unmarshal response JSON from coveralls: %s\n%s", err, bodyBytes)
}
if response.Error {
return errors.New(response.Message)
}
fmt.Println(response.Message)
fmt.Println(response.URL)
return nil
}
func getGithubEvent() map[string]interface{} {
jsonFilePath := os.Getenv("GITHUB_EVENT_PATH")
if jsonFilePath == "" {
return nil
}
jsonFile, err := os.Open(jsonFilePath)
if err != nil {
log.Fatal(err)
}
defer jsonFile.Close()
jsonByte, _ := ioutil.ReadAll(jsonFile)
// unmarshal the json into a release event
var event map[string]interface{}
err = json.Unmarshal(jsonByte, &event)
if err != nil {
log.Fatal(err)
}
return event
}
func main() {
if err := process(); err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err)
os.Exit(1)
}
}

5
vendor/github.com/mattn/goveralls/renovate.json generated vendored Normal file
View File

@ -0,0 +1,5 @@
{
"extends": [
"config:base"
]
}

26
vendor/github.com/mohae/deepcopy/.gitignore generated vendored Normal file
View File

@ -0,0 +1,26 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*~
*.out
*.log

11
vendor/github.com/mohae/deepcopy/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,11 @@
language: go
go:
- tip
matrix:
allow_failures:
- go: tip
script:
- go test ./...

21
vendor/github.com/mohae/deepcopy/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Joel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

8
vendor/github.com/mohae/deepcopy/README.md generated vendored Normal file
View File

@ -0,0 +1,8 @@
deepCopy
========
[![GoDoc](https://godoc.org/github.com/mohae/deepcopy?status.svg)](https://godoc.org/github.com/mohae/deepcopy)[![Build Status](https://travis-ci.org/mohae/deepcopy.png)](https://travis-ci.org/mohae/deepcopy)
DeepCopy makes deep copies of things: unexported field values are not copied.
## Usage
cpy := deepcopy.Copy(orig)

125
vendor/github.com/mohae/deepcopy/deepcopy.go generated vendored Normal file
View File

@ -0,0 +1,125 @@
// deepcopy makes deep copies of things. A standard copy will copy the
// pointers: deep copy copies the values pointed to. Unexported field
// values are not copied.
//
// Copyright (c)2014-2016, Joel Scoble (github.com/mohae), all rights reserved.
// License: MIT, for more details check the included LICENSE file.
package deepcopy
import (
"reflect"
"time"
)
// Interface for delegating copy process to type
type Interface interface {
DeepCopy() interface{}
}
// Iface is an alias to Copy; this exists for backwards compatibility reasons.
func Iface(iface interface{}) interface{} {
return Copy(iface)
}
// Copy creates a deep copy of whatever is passed to it and returns the copy
// in an interface{}. The returned value will need to be asserted to the
// correct type.
func Copy(src interface{}) interface{} {
if src == nil {
return nil
}
// Make the interface a reflect.Value
original := reflect.ValueOf(src)
// Make a copy of the same type as the original.
cpy := reflect.New(original.Type()).Elem()
// Recursively copy the original.
copyRecursive(original, cpy)
// Return the copy as an interface.
return cpy.Interface()
}
// copyRecursive does the actual copying of the interface. It currently has
// limited support for what it can handle. Add as needed.
func copyRecursive(original, cpy reflect.Value) {
// check for implement deepcopy.Interface
if original.CanInterface() {
if copier, ok := original.Interface().(Interface); ok {
cpy.Set(reflect.ValueOf(copier.DeepCopy()))
return
}
}
// handle according to original's Kind
switch original.Kind() {
case reflect.Ptr:
// Get the actual value being pointed to.
originalValue := original.Elem()
// if it isn't valid, return.
if !originalValue.IsValid() {
return
}
cpy.Set(reflect.New(originalValue.Type()))
copyRecursive(originalValue, cpy.Elem())
case reflect.Interface:
// If this is a nil, don't do anything
if original.IsNil() {
return
}
// Get the value for the interface, not the pointer.
originalValue := original.Elem()
// Get the value by calling Elem().
copyValue := reflect.New(originalValue.Type()).Elem()
copyRecursive(originalValue, copyValue)
cpy.Set(copyValue)
case reflect.Struct:
t, ok := original.Interface().(time.Time)
if ok {
cpy.Set(reflect.ValueOf(t))
return
}
// Go through each field of the struct and copy it.
for i := 0; i < original.NumField(); i++ {
// The Type's StructField for a given field is checked to see if StructField.PkgPath
// is set to determine if the field is exported or not because CanSet() returns false
// for settable fields. I'm not sure why. -mohae
if original.Type().Field(i).PkgPath != "" {
continue
}
copyRecursive(original.Field(i), cpy.Field(i))
}
case reflect.Slice:
if original.IsNil() {
return
}
// Make a new slice and copy each element.
cpy.Set(reflect.MakeSlice(original.Type(), original.Len(), original.Cap()))
for i := 0; i < original.Len(); i++ {
copyRecursive(original.Index(i), cpy.Index(i))
}
case reflect.Map:
if original.IsNil() {
return
}
cpy.Set(reflect.MakeMap(original.Type()))
for _, key := range original.MapKeys() {
originalValue := original.MapIndex(key)
copyValue := reflect.New(originalValue.Type()).Elem()
copyRecursive(originalValue, copyValue)
copyKey := Copy(key.Interface())
cpy.SetMapIndex(reflect.ValueOf(copyKey), copyValue)
}
default:
cpy.Set(original)
}
}

7
vendor/github.com/ory/fosite/.gitignore generated vendored Normal file
View File

@ -0,0 +1,7 @@
.idea
*.iml
.cover
*.log
*.exe
cover.out
vendor/

17
vendor/github.com/ory/fosite/.golangci.yml generated vendored Normal file
View File

@ -0,0 +1,17 @@
linters:
enable:
- gosec
disable:
- ineffassign
- deadcode
- unused
- structcheck
- errcheck
- gosimple
- bodyclose
- staticcheck
run:
skip-files:
- ".+_test.go"
- ".+_test_.+.go"

16
vendor/github.com/ory/fosite/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,16 @@
language: go
go_import_path: github.com/ory/fosite
go:
- "1.14"
install:
- go install github.com/mattn/goveralls
- go install github.com/ory/go-acc
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.24.0
script:
- golangci-lint run
- go-acc -o coverage.txt ./... -- -failfast -timeout=20m
- goveralls -coverprofile="coverage.txt"

141
vendor/github.com/ory/fosite/CONTRIBUTING.md generated vendored Normal file
View File

@ -0,0 +1,141 @@
<!--
Thank you for contributing changes to this document! Because we use a central repository
to synchronize this file across all our repositories, make sure to make your edits
in the correct file, which you can find here:
https://github.com/ory/meta/blob/master/templates/repository/CONTRIBUTING.md
-->
# Contributing to ORY Fosite
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [Introduction](#introduction)
- [Contributing Code](#contributing-code)
- [Disclosing vulnerabilities](#disclosing-vulnerabilities)
- [Code Style](#code-style)
- [Documentation](#documentation)
- [Pull request procedure](#pull-request-procedure)
- [Communication](#communication)
- [Conduct](#conduct)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## Introduction
Please note: We take ORY Fosite's security and our users' trust very
seriously. If you believe you have found a security issue in ORY Fosite,
please responsibly disclose by contacting us at hi@ory.sh.
First: if you're unsure or afraid of anything, just ask or submit the issue or
pull request anyways. You won't be yelled at for giving it your best effort. The
worst that can happen is that you'll be politely asked to change something. We
appreciate any sort of contributions, and don't want a wall of rules to get in
the way of that.
That said, if you want to ensure that a pull request is likely to be merged,
talk to us! You can find out our thoughts and ensure that your contribution
won't clash or be obviated by ORY Fosite's normal direction. A great way to
do this is via the [ORY Community](https://community.ory.sh/) or join the
[ORY Chat](https://www.ory.sh/chat).
## Contributing Code
Unless you are fixing a known bug, we **strongly** recommend discussing it with
the core team via a GitHub issue or [in our chat](https://www.ory.sh/chat)
before getting started to ensure your work is consistent with ORY Fosite's
roadmap and architecture.
All contributions are made via pull request. Note that **all patches from all
contributors get reviewed**. After a pull request is made other contributors
will offer feedback, and if the patch passes review a maintainer will accept it
with a comment. When pull requests fail testing, authors are expected to update
their pull requests to address the failures until the tests pass and the pull
request merges successfully.
At least one review from a maintainer is required for all patches (even patches
from maintainers).
Reviewers should leave a "LGTM" comment once they are satisfied with the patch.
If the patch was submitted by a maintainer with write access, the pull request
should be merged by the submitter after review.
## Disclosing vulnerabilities
Please disclose vulnerabilities exclusively to
[security@ory.sh](mailto:security@ory.sh). Do not use GitHub issues.
## Code Style
Please follow these guidelines when formatting source code:
- Go code should match the output of `gofmt -s` and pass `golangci-lint run`.
- NodeJS and JavaScript code should be prettified using `npm run format` where
appropriate.
## Documentation
Please provide documentation when changing, removing, or adding features.
Documentation resides in the project's [docs](docs) folder. Generate API and
configuration reference documentation using `cd docs; npm run gen`.
For further instructions please head over to [docs/README.md](docs/README.md).
## Pull request procedure
To make a pull request, you will need a GitHub account; if you are unclear on
this process, see GitHub's documentation on
[forking](https://help.github.com/articles/fork-a-repo) and
[pull requests](https://help.github.com/articles/using-pull-requests). Pull
requests should be targeted at the `master` branch. Before creating a pull
request, go through this checklist:
1. Create a feature branch off of `master` so that changes do not get mixed up.
1. [Rebase](http://git-scm.com/book/en/Git-Branching-Rebasing) your local
changes against the `master` branch.
1. Run the full project test suite with the `go test ./...` (or equivalent)
command and confirm that it passes.
1. Run `gofmt -s` (if the project is written in Go).
1. Ensure that each commit has a subsystem prefix (ex: `controller:`).
Pull requests will be treated as "review requests," and maintainers will give
feedback on the style and substance of the patch.
Normally, all pull requests must include tests that test your change.
Occasionally, a change will be very difficult to test for. In those cases,
please include a note in your commit message explaining why.
## Communication
We use [Slack](https://www.ory.sh/chat). You are welcome to drop in and ask
questions, discuss bugs, etc.
## Conduct
Whether you are a regular contributor or a newcomer, we care about making this
community a safe place for you and we've got your back.
- We are committed to providing a friendly, safe and welcoming environment for
all, regardless of gender, sexual orientation, disability, ethnicity,
religion, or similar personal characteristic.
- Please avoid using nicknames that might detract from a friendly, safe and
welcoming environment for all.
- Be kind and courteous. There is no need to be mean or rude.
- We will exclude you from interaction if you insult, demean or harass anyone.
In particular, we do not tolerate behavior that excludes people in socially
marginalized groups.
- Private harassment is also unacceptable. No matter who you are, if you feel
you have been or are being harassed or made uncomfortable by a community
member, please contact one of the channel ops or a member of the ORY
Fosite core team immediately.
- Likewise any spamming, trolling, flaming, baiting or other attention-stealing
behaviour is not welcome.
We welcome discussion about creating a welcoming, safe, and productive
environment for the community. If you have any questions, feedback, or concerns
[please let us know](https://www.ory.sh/chat).

653
vendor/github.com/ory/fosite/HISTORY.md generated vendored Normal file
View File

@ -0,0 +1,653 @@
This is a list of breaking changes. As long as `1.0.0` is not released, breaking changes will be addressed as minor version
bumps (`0.1.0` -> `0.2.0`).
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [0.28.0](#0280)
- [0.27.0](#0270)
- [Conceptual Changes](#conceptual-changes)
- [API Changes](#api-changes)
- [0.26.0](#0260)
- [0.24.0](#0240)
- [Breaking change(s)](#breaking-changes)
- [`fosite/handler/oauth2.JWTStrategy`](#fositehandleroauth2jwtstrategy)
- [`OpenIDConnectRequestValidator.ValidatePrompt`](#openidconnectrequestvalidatorvalidateprompt)
- [0.23.0](#0230)
- [Breaking change(s)](#breaking-changes-1)
- [`Hasher`](#hasher)
- [0.22.0](#0220)
- [Breaking change(s)](#breaking-changes-2)
- [`JWTStrategy`](#jwtstrategy)
- [0.21.0](#0210)
- [Changes to parsing of OAuth 2.0 Client `response_types`](#changes-to-parsing-of-oauth-20-client-response_types)
- [`openid.DefaultStrategy` field name changed](#openiddefaultstrategy-field-name-changed)
- [`oauth2.RS256JWTStrategy` was renamed and field name changed](#oauth2rs256jwtstrategy-was-renamed-and-field-name-changed)
- [Adds `private_key_jwt` client authentication method](#adds-private_key_jwt-client-authentication-method)
- [Response Type `id_token` no longer required for authorize_code flow](#response-type-id_token-no-longer-required-for-authorize_code-flow)
- [0.20.0](#0200)
- [Breaking Changes](#breaking-changes)
- [JWT Claims](#jwt-claims)
- [`AuthorizeCodeStorage`](#authorizecodestorage)
- [0.19.0](#0190)
- [0.18.0](#0180)
- [0.17.0](#0170)
- [0.16.0](#0160)
- [0.15.0](#0150)
- [0.14.0](#0140)
- [0.13.0](#0130)
- [Breaking changes](#breaking-changes)
- [0.12.0](#0120)
- [Breaking changes](#breaking-changes-1)
- [Improved cryptographic methods](#improved-cryptographic-methods)
- [0.11.0](#0110)
- [Non-breaking changes](#non-breaking-changes)
- [Storage adapter](#storage-adapter)
- [Reducing use of gomock](#reducing-use-of-gomock)
- [Breaking Changes](#breaking-changes-1)
- [`fosite/handler/oauth2.AuthorizeCodeGrantStorage` was removed](#fositehandleroauth2authorizecodegrantstorage-was-removed)
- [`fosite/handler/oauth2.RefreshTokenGrantStorage` was removed](#fositehandleroauth2refreshtokengrantstorage-was-removed)
- [`fosite/handler/oauth2.AuthorizeCodeGrantStorage` was removed](#fositehandleroauth2authorizecodegrantstorage-was-removed-1)
- [WildcardScopeStrategy](#wildcardscopestrategy)
- [Refresh tokens and authorize codes are no longer JWTs](#refresh-tokens-and-authorize-codes-are-no-longer-jwts)
- [Delete access tokens when persisting refresh session](#delete-access-tokens-when-persisting-refresh-session)
- [0.10.0](#0100)
- [0.9.0](#090)
- [0.8.0](#080)
- [Breaking changes](#breaking-changes-2)
- [`ClientManager`](#clientmanager)
- [`OAuth2Provider`](#oauth2provider)
- [0.7.0](#070)
- [0.6.0](#060)
- [0.5.0](#050)
- [0.4.0](#040)
- [0.3.0](#030)
- [0.2.0](#020)
- [0.1.0](#010)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## 0.28.0
This version (re-)introduces refresh token lifespans. Per default, this feature is enabled and set to 30 days.
If a refresh token has not been used within 30 days, it will expire.
To disable refresh token lifespans (previous behaviour), set `compose.Config.RefreshTokenLifespan = -1`.
## 0.27.0
This PR adds the ability to specify a target audience for OAuth 2.0 Access Tokens.
### Conceptual Changes
From now on, `scope` and `audience` will be checked against the client's whitelisted scope and audience on every
refresh token exchange. This prevents clients, which no longer are allowed to request a certain audience or scope,
to keep using those values with existing refresh tokens.
### API Changes
```go
type fosite.Client interface {
+ // GetAudience returns the allowed audience(s) for this client.
+ GetAudience() Arguments
}
```
```go
type fosite.Request struct {
- Scopes Argument
+ RequestedScope Argument
- GrantedScopes Argument
+ GrantedScope Argument
}
```
```go
type fosite.Requester interface {
+ // GetRequestedAudience returns the requested audiences for this request.
+ GetRequestedAudience() (audience Arguments)
+ // SetRequestedAudience sets the requested audienc.
+ SetRequestedAudience(audience Arguments)
+ // GetGrantedAudience returns all granted scopes.
+ GetGrantedAudience() (grantedAudience Arguments)
+ // GrantAudience marks a request's audience as granted.
+ GrantAudience(audience string)
}
```
```go
type fosite/token/jwt.JWTClaimsContainer interface {
- // With returns a copy of itself with expiresAt and scope set to the given values.
- With(expiry time.Time, scope, audience []string) JWTClaimsContainer
+ // With returns a copy of itself with expiresAt, scope, audience set to the given values.
+ With(expiry time.Time, scope, audience []string) JWTClaimsContainer
}
```
## 0.26.0
This release makes it easier to define custom JWT Containers for access tokens when using the JWT strategy. To do that,
the following signatures have changed:
```go
// github.com/ory/fosite/handler/oauth2
type JWTSessionContainer interface {
// GetJWTClaims returns the claims.
- GetJWTClaims() *jwt.JWTClaims
+ GetJWTClaims() jwt.JWTClaimsContainer
// GetJWTHeader returns the header.
GetJWTHeader() *jwt.Headers
fosite.Session
}
```
```go
+ type JWTClaimsContainer interface {
+ // With returns a copy of itself with expiresAt and scope set to the given values.
+ With(expiry time.Time, scope []string) JWTClaimsContainer
+
+ // WithDefaults returns a copy of itself with issuedAt and issuer set to the given default values. If those
+ // values are already set in the claims, they will not be updated.
+ WithDefaults(iat time.Time, issuer string) JWTClaimsContainer
+
+ // ToMapClaims returns the claims as a github.com/dgrijalva/jwt-go.MapClaims type.
+ ToMapClaims() jwt.MapClaims
+ }
```
All default session implementations have been updated to reflect this change. If you define custom session, this patch
will affect you.
## 0.24.0
This release addresses areas where the go context was missing or not propagated down the call path properly.
### Breaking change(s)
#### `fosite/handler/oauth2.JWTStrategy`
The [`fosite/handler/oauth2.JWTStrategy`](https://github.com/ory/fosite/blob/master/handler/oauth2/strategy.go) interface changed as a context
parameter was added to its method signature:
```go
type JWTStrategy interface {
- Validate(tokenType fosite.TokenType, token string) (requester fosite.Requester, err error)
+ Validate(ctx context.Context, tokenType fosite.TokenType, token string) (requester fosite.Requester, err error)
}
```
#### `OpenIDConnectRequestValidator.ValidatePrompt`
The [`OpenIDConnectRequestValidator.ValidatePrompt`](https://github.com/ory/fosite/blob/master/handler/openid/validator.go)
method signature was updated to take a go context as its first parameter:
```go
- func (v *OpenIDConnectRequestValidator) ValidatePrompt(req fosite.AuthorizeRequester) error {
+ func (v *OpenIDConnectRequestValidator) ValidatePrompt(ctx context.Context, req fosite.AuthorizeRequester) error {
```
## 0.23.0
This releases addresses inconsistencies in some of the public interfaces by passing in the go context to their signatures.
### Breaking change(s)
#### `Hasher`
The [`Hasher`](https://github.com/ory/fosite/blob/master/hash.go) interface
changed as a context parameter was added to its method signatures:
```go
type Hasher interface {
- Compare(hash, data []byte) error
+ Compare(ctx context.Context, hash, data []byte) error
- Hash(data []byte) ([]byte, error)
+ Hash(ctx context.Context, data []byte) ([]byte, error)
}
```
## 0.22.0
This releases addresses inconsistencies in some of the public interfaces by passing in the go context to their signatures.
### Breaking change(s)
#### `JWTStrategy`
The [`JWTStrategy`](https://github.com/ory/fosite/blob/master/token/jwt/jwt.go) interface
changed as a context parameter was added to its method signatures:
```go
type JWTStrategy interface {
- Generate(claims jwt.Claims, header Mapper) (string, string, error)
+ Generate(ctx context.Context, claims jwt.Claims, header Mapper) (string, string, error)
- Validate(token string) (string, error)
+ Validate(ctx context.Context, token string) (string, error)
- GetSignature(token string) (string, error)
+ GetSignature(ctx context.Context, token string) (string, error)
- Hash(in []byte) ([]byte, error)
+ Hash(ctx context.Context, in []byte) ([]byte, error)
- Decode(token string) (*jwt.Token, error)
+ Decode(ctx context.Context, token string) (*jwt.Token, error)
GetSigningMethodLength() int
}
```
## 0.21.0
This release improves compatibility with the OpenID Connect Dynamic Client Registration 1.0 specification.
### Changes to parsing of OAuth 2.0 Client `response_types`
Previously, when response types such as `code token id_token` were requested (OpenID Connect Hybrid Flow) it was enough
for the client to have `response_types=["code", "token", "id_token"]`. This is however incompatible with the
OpenID Connect Dynamic Client Registration 1.0 spec which dictates that the `response_types` have to match exactly.
Assuming you are requesting `&response_types=code+token+id_token`, your client should have `response_types=["code token id_token"]`,
if other response types are required (e.g. `&response_types=code`, `&response_types=token`) they too must be included:
`response_types=["code", "token", "code token id_token"]`.
### `openid.DefaultStrategy` field name changed
Field `RS256JWTStrategy` was renamed to `JWTStrategy` and now relies on an interface instead of a concrete struct.
### `oauth2.RS256JWTStrategy` was renamed and field name changed
The strategy `oauth2.RS256JWTStrategy` was renamed to `oauth2.DefaultJWTStrategy` and now accepts an interface that
implements `jwt.JWTStrategy` instead of directly relying on `jwt.RS256JWTStrategy`. For this reason,
the field `RS256JWTStrategy` was renamed to `JWTStrategy`
### Adds `private_key_jwt` client authentication method
This patch adds the ability to perform the [`private_key_jwt` client authentication method](http://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication)
defined in the OpenID Connect specification. Please note that method `client_secret_jwt` is not supported because of the BCrypt hashing strategy.
For this strategy to work, you must set the `TokenURL` field of the `compose.Config` object to the authorization server's
Token URL.
If you would like to support this authentication method, your `Client` implementation must also implement `fosite.DefaultOpenIDConnectClient`
and then, for example, `GetTokenEndpointAuthMethod()` should return `private_key_jwt`.
### Response Type `id_token` no longer required for authorize_code flow
The `authorize_code` [does not require](https://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata)
the `id_token` response type to be available when performing the OpenID Connect flow:
> grant_types
> OPTIONAL. JSON array containing a list of the OAuth 2.0 Grant Types that the Client is declaring that it will restrict itself to using. The Grant Type values used by OpenID Connect are:
>
> authorization_code: The Authorization Code Grant Type described in OAuth 2.0 Section 4.1.
> implicit: The Implicit Grant Type described in OAuth 2.0 Section 4.2.
> refresh_token: The Refresh Token Grant Type described in OAuth 2.0 Section 6.
>
> The following table lists the correspondence between response_type values that the Client will use and grant_type values that MUST be included in the registered grant_types list:
>
> code: authorization_code
> id_token: implicit
> token id_token: implicit
> code id_token: authorization_code, implicit
> code token: authorization_code, implicit
> code token id_token: authorization_code, implicit
>
> If omitted, the default is that the Client will use only the authorization_code Grant Type.
Before this patch, the `id_token` response type was required whenever an ID Token was requested. This patch changes that.
## 0.20.0
This release implements an OAuth 2.0 Best Practice with regards to revoking already issued access and refresh tokens
if an authorization code is used more than one time.
## Breaking Changes
### JWT Claims
- `github.com/ory/fosite/token/jwt.JWTClaims.Audience` is no longer a `string`, but a string slice `[]string`.
- `github.com/ory/fosite/handler/openid.IDTokenClaims` is no longer a `string`, but a string slice `[]string`.
### `AuthorizeCodeStorage`
This improves security as, in the event of an authorization code being leaked, all associated tokens are revoked. To
implement this feature, a breaking change had to be introduced. The `github.com/ory/fosite/handler/oauth2.AuthorizeCodeStorage`
interface changed as follows:
- `DeleteAuthorizeCodeSession(ctx context.Context, code string) (err error)` has been removed from the interface and
is no longer used by this library.
- `InvalidateAuthorizeCodeSession(ctx context.Context, code string) (err error)` has been introduced.
- The error `github.com/ory/fosite/handler/oauth2.ErrInvalidatedAuthorizeCode` has been added.
The following documentation sheds light on how you should update your storage adapter:
```
// ErrInvalidatedAuthorizeCode is an error indicating that an authorization code has been
// used previously.
var ErrInvalidatedAuthorizeCode = errors.New("Authorization code has ben invalidated")
// AuthorizeCodeStorage handles storage requests related to authorization codes.
type AuthorizeCodeStorage interface {
// GetAuthorizeCodeSession stores the authorization request for a given authorization code.
CreateAuthorizeCodeSession(ctx context.Context, code string, request fosite.Requester) (err error)
// GetAuthorizeCodeSession hydrates the session based on the given code and returns the authorization request.
// If the authorization code has been invalidated with `InvalidateAuthorizeCodeSession`, this
// method should return the ErrInvalidatedAuthorizeCode error.
//
// Make sure to also return the fosite.Requester value when returning the ErrInvalidatedAuthorizeCode error!
GetAuthorizeCodeSession(ctx context.Context, code string, session fosite.Session) (request fosite.Requester, err error)
// InvalidateAuthorizeCodeSession is called when an authorize code is being used. The state of the authorization
// code should be set to invalid and consecutive requests to GetAuthorizeCodeSession should return the
// ErrInvalidatedAuthorizeCode error.
InvalidateAuthorizeCodeSession(ctx context.Context, code string) (err error)
}
```
## 0.19.0
This release improves the OpenID Connect vaildation strategy which now properly handles `prompt`, `max_age`, and `id_token_hint`
at the `/oauth2/auth` endpoint instead of the `/oauth2/token` endpoint.
To achieve this, the `OpenIDConnectRequestValidator` has been modified and now requires a `jwt.JWTStrategy` (implemented by,
for example `jwt.RS256JWTStrategy`).
The compose package has been updated accordingly. You should not expect any major breaking changes from this release.
## 0.18.0
This release allows the introspection handler to return the token type (e.g. `access_token`, `refresh_token`) of the
introspected token. To achieve that, some breaking API changes have been introduced:
* `OAuth2.IntrospectToken(ctx context.Context, token string, tokenType TokenType, session Session, scope ...string) (AccessRequester, error)` is now `OAuth2.IntrospectToken(ctx context.Context, token string, tokenType TokenType, session Session, scope ...string) (TokenType, AccessRequester, error)`.
* `TokenIntrospector.IntrospectToken(ctx context.Context, token string, tokenType TokenType, accessRequest AccessRequester, scopes []string) (error)` is now `TokenIntrospector.IntrospectToken(ctx context.Context, token string, tokenType TokenType, accessRequest AccessRequester, scopes []string) (TokenType, error)`.
This patch also resolves a misconfigured json key in the `IntrospectionResponse` struct. `AccessRequester AccessRequester json:",extra"` is now properly declared as `AccessRequester AccessRequester json:"extra"`.
## 0.17.0
This release resolves a security issue (reported by [platform.sh](https://www.platform.sh)) related to potential storage implementations.
This library used to pass all of the request body from both authorize and token endpoints to the storage adapters. As some of these values
are needed in consecutive requests, some storage adapters chose to drop the full body to the database.
This implied that confidential parameters, such as the `client_secret` which can be passed in the request body since
version 0.15.0, were stored as key/value pairs in plaintext in the database. While most client secrets are generated
programmatically (as opposed to set by the user), it's a considerable security issue nonetheless.
The issue has been resolved by sanitizing the request body and only including those values truly required by their
respective handlers. This lead to two breaking changes in the API:
1. The `fosite.Requester` interface has a new method `Sanitize(allowedParameters []string) Requester` which returns
a sanitized clone of the method receiver. If you do not use your own `fosite.Requester` implementation, this won't affect you.
2. If you use the PKCE handler, you will have to add three new methods to your storage implementation. The methods
to be added work exactly like, for example `CreateAuthorizeCodeSession`. A reference implementation can be found in
[./storage/memory.go](./storage/memory.go). The method signatures are as follows:
```go
type PKCERequestStorage interface {
GetPKCERequestSession(ctx context.Context, signature string, session fosite.Session) (fosite.Requester, error)
CreatePKCERequestSession(ctx context.Context, signature string, requester fosite.Requester) error
DeletePKCERequestSession(ctx context.Context, signature string) error
}
```
We encourage you to upgrade to this release and check your storage implementations and potentially remove old data.
We would like to thank [platform.sh](https://www.platform.sh) for sponsoring the development of a patch that resolves this
issue.
## 0.16.0
This patch introduces `SendDebugMessagesToClients` to the Fosite struct which enables/disables sending debug information to
clients. Debug information may contain sensitive information as it forwards error messages from, for example, storage
implementations. For this reason, `RevealDebugPayloads` defaults to false. Keep in mind that the information may be
very helpful when specific OAuth 2.0 requests fail and we generally recommend displaying debug information.
Additionally, error keys for JSON changed which caused a new minor version, speicifically
[`statusCode` was changed to `status_code`](https://github.com/ory/fosite/pull/242/files#diff-dd25e0e0a594c3f3592c1c717039b85eR221).
## 0.15.0
This release focuses on improving compatibility with OpenID Connect Certification and better error context.
* Error handling is improved by explicitly adding debug information (e.g. "Token invalid because it was not found
in the database") to the error object. Previously, the original error was prepended which caused weird formatting issues.
* Allows client credentials in POST body at the `/oauth2/token` endpoint. Please note that this method is not recommended
to be used, unless the client making the request is unable to use HTTP Basic Authorization.
* Allows public clients (without secret) to access the `/oauth2/token` endpoint which was previously only possible by adding an arbitrary
secret.
This release has no breaking changes to the external API but due to the nature of the changes, it is released
as a new major version.
## 0.14.0
Improves error contexts. A breaking code changes to the public API was reverted with 0.14.1.
## 0.13.0
### Breaking changes
`glide` was replaced with `dep`.
## 0.12.0
### Breaking changes
#### Improved cryptographic methods
* The minimum required secret length used to generate signatures of access tokens has increased from 16 to 32 byte.
* The algorithm used to generate access tokens using the HMAC-SHA strategy has changed from HMAC-SHA256 to HMAC-SHA512.
## 0.11.0
### Non-breaking changes
#### Storage adapter
To simplify the storage adapter logic, and also reduce the likelihoods of bugs within the storage adapter, the
interface was greatly simplified. Specifically, these two methods have been removed:
* `PersistRefreshTokenGrantSession(ctx context.Context, requestRefreshSignature, accessSignature, refreshSignature string, request fosite.Requester) error`
* `PersistAuthorizeCodeGrantSession(ctx context.Context, authorizeCode, accessSignature, refreshSignature string, request fosite.Requester) error`
For this change, you don't need to do anything. You can however simply delete those two methods from your store.
#### Reducing use of gomock
In the long term, fosite should remove all gomocks and instead test against the internal implementations. This
will increase iterations per line during tests and reduce annoying mock updates.
### Breaking Changes
#### `fosite/handler/oauth2.AuthorizeCodeGrantStorage` was removed
`AuthorizeCodeGrantStorage` was used specifically in the composer. Refactor references to `AuthorizeCodeGrantStorage` with `CoreStorage`.
#### `fosite/handler/oauth2.RefreshTokenGrantStorage` was removed
`RefreshTokenGrantStorage` was used specifically in the composer. Refactor references to `RefreshTokenGrantStorage` with `CoreStorage`.
#### `fosite/handler/oauth2.AuthorizeCodeGrantStorage` was removed
`AuthorizeCodeGrantStorage` was used specifically in the composer. Refactor references to `AuthorizeCodeGrantStorage` with `CoreStorage`.
#### WildcardScopeStrategy
A new [scope strategy](https://github.com/ory/fosite/pull/187) was introduced called `WildcardScopeStrategy`. This strategy is now the default when using
the composer. To set the HierarchicScopeStrategy strategy, do:
```
import "github.com/ory/fosite/compose"
var config = &compose.Config{
ScopeStrategy: fosite.HierarchicScopeStrategy,
}
```
#### Refresh tokens and authorize codes are no longer JWTs
Using JWTs for refresh tokens and authorize codes did not make sense:
1. Refresh tokens are long-living credentials, JWTs require an expiry date.
2. Refresh tokens are never validated client-side, only server-side. Thus access to the store is available.
3. Authorize codes are never validated client-side, only server-side.
Also, one compose method changed due to this:
```go
package compose
// ..
- func NewOAuth2JWTStrategy(key *rsa.PrivateKey) *oauth2.RS256JWTStrategy
+ func NewOAuth2JWTStrategy(key *rsa.PrivateKey, strategy *oauth2.HMACSHAStrategy) *oauth2.RS256JWTStrategy
```
#### Delete access tokens when persisting refresh session
Please delete access tokens in your store when you persist a refresh session. This increases security. Here
is an example of how to do that using only existing methods:
```go
func (s *MemoryStore) PersistRefreshTokenGrantSession(ctx context.Context, originalRefreshSignature, accessSignature, refreshSignature string, request fosite.Requester) error {
if ts, err := s.GetRefreshTokenSession(ctx, originalRefreshSignature, nil); err != nil {
return err
} else if err := s.RevokeAccessToken(ctx, ts.GetID()); err != nil {
return err
} else if err := s.RevokeRefreshToken(ctx, ts.GetID()); err != nil {
return err
} else if err := s.CreateAccessTokenSession(ctx, accessSignature, request); err != nil {
return err
} else if err := s.CreateRefreshTokenSession(ctx, refreshSignature, request); err != nil {
return err
}
return nil
}
```
## 0.10.0
It is no longer possible to introspect authorize codes, and passing scopes to the introspector now also checks
refresh token scopes.
## 0.9.0
This patch adds the ability to pass a custom hasher to `compose.Compose`, which is a breaking change. You can pass nil for the fosite default hasher:
```
package compose
-func Compose(config *Config, storage interface{}, strategy interface{}, factories ...Factory) fosite.OAuth2Provider {
+func Compose(config *Config, storage interface{}, strategy interface{}, hasher fosite.Hasher, factories ...Factory) fosite.OAuth2Provider {
```
## 0.8.0
This patch addresses some inconsistencies in the public interfaces. Also
remaining references to the old repository location at `ory-am/fosite`
where updated to `ory/fosite`.
### Breaking changes
#### `ClientManager`
The [`ClientManager`](https://github.com/ory/fosite/blob/master/client_manager.go) interface
changed, as a context parameter was added:
```go
type ClientManager interface {
// GetClient loads the client by its ID or returns an error
// if the client does not exist or another error occurred.
- GetClient(id string) (Client, error)
+ GetClient(ctx context.Context, id string) (Client, error)
}
```
#### `OAuth2Provider`
The [OAuth2Provider](https://github.com/ory/fosite/blob/master/oauth2.go) interface changed,
as the need for passing down `*http.Request` was removed. This is justifiable
because `NewAuthorizeRequest` and `NewAccessRequest` already contain `*http.Request`.
The public api of those two methods changed:
```go
- NewAuthorizeResponse(ctx context.Context, req *http.Request, requester AuthorizeRequester, session Session) (AuthorizeResponder, error)
+ NewAuthorizeResponse(ctx context.Context, requester AuthorizeRequester, session Session) (AuthorizeResponder, error)
- NewAccessResponse(ctx context.Context, req *http.Request, requester AccessRequester) (AccessResponder, error)
+ NewAccessResponse(ctx context.Context, requester AccessRequester) (AccessResponder, error)
```
## 0.7.0
Breaking changes:
* Replaced `"golang.org/x/net/context"` with `"context"`.
* Move the repo from `github.com/ory-am/fosite` to `github.com/ory/fosite`
## 0.6.0
A bug related to refresh tokens was found. To mitigate it, a `Clone()` method has been introduced to the `fosite.Session` interface.
If you use a custom session object, this will be a breaking change. Fosite's default sessions have been upgraded and no additional
work should be required. If you use your own session struct, we encourage using package `gob/encoding` to deep-copy it in `Clone()`.
## 0.5.0
Breaking changes:
* `compose.OpenIDConnectExplicit` is now `compose.OpenIDConnectExplicitFactory`
* `compose.OpenIDConnectImplicit` is now `compose.OpenIDConnectImplicitFactory`
* `compose.OpenIDConnectHybrid` is now `compose.OpenIDConnectHybridFactory`
* The token introspection handler is no longer added automatically by `compose.OAuth2*`. Add `compose.OAuth2TokenIntrospectionFactory`
to your composer if you need token introspection.
* Session refactor:
* The HMACSessionContainer was removed and replaced by `fosite.Session` / `fosite.DefaultSession`. All sessions
must now implement this signature. The new session interface allows for better expiration time handling.
* The OpenID `DefaultSession` signature changed as well, it is now implementing the `fosite.Session` interface
## 0.4.0
Breaking changes:
* `./fosite-example` is now a separate repository: https://github.com/ory-am/fosite-example
* `github.com/ory-am/fosite/fosite-example/pkg.Store` is now `github.com/ory-am/fosite/storage.MemoryStore`
* `fosite.Client` has now a new method called `IsPublic()` which can be used to identify public clients who do not own a client secret
* All grant types except the client_credentials grant now allow public clients. public clients are usually mobile apps and single page apps.
* `TokenValidator` is now `TokenIntrospector`, `TokenValidationHandlers` is now `TokenIntrospectionHandlers`.
* `TokenValidator.ValidateToken` is now `TokenIntrospector.IntrospectToken`
* `fosite.OAuth2Provider.NewIntrospectionRequest()` has been added
* `fosite.OAuth2Provider.WriteIntrospectionError()` has been added
* `fosite.OAuth2Provider.WriteIntrospectionResponse()` has been added
## 0.3.0
* Updated jwt-go from 2.7.0 to 3.0.0
## 0.2.0
Breaking changes:
* Token validation refactored: `ValidateRequestAuthorization` is now `Validate` and does not require a http request
but instead a token and a token hint. A token can be anything, including authorization codes, refresh tokens,
id tokens, ...
* Remove mandatory scope: The mandatory scope (`fosite`) has been removed as it has proven impractical.
* Allowed OAuth2 Client scopes are now being set with `scope` instead of `granted_scopes` when using the DefaultClient.
* There is now a scope matching strategy that can be replaced.
* OAuth2 Client scopes are now checked on every grant type.
* Handler subpackages such as `core/client` or `oidc/explicit` have been merged and moved one level up
* `handler/oidc` is now `handler/openid`
* `handler/core` is now `handler/oauth2`
## 0.1.0
Initial release

201
vendor/github.com/ory/fosite/LICENSE generated vendored Normal file
View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

2
vendor/github.com/ory/fosite/MAINTAINERS generated vendored Normal file
View File

@ -0,0 +1,2 @@
Aeneas Rekkas <aeneas@ory.am> (github: arekkas)
Thomas Aidan Curran <thomasaidancurran@gmail.com> (github: tacurran)

5
vendor/github.com/ory/fosite/Makefile generated vendored Normal file
View File

@ -0,0 +1,5 @@
format:
goreturns -w -local github.com/ory $$(listx .)
test:
go test ./...

434
vendor/github.com/ory/fosite/README.md generated vendored Normal file
View File

@ -0,0 +1,434 @@
<h1 align="center"><img src="./docs/image/banner_fosite.png" alt="ORY Fosite - Security-first OAuth2 framework"></h1>
[![Build Status](https://travis-ci.org/ory/fosite.svg?branch=master)](https://travis-ci.org/ory/fosite?branch=master)
[![Coverage Status](https://coveralls.io/repos/ory/fosite/badge.svg?branch=master&service=github&foo)](https://coveralls.io/github/ory/fosite?branch=master)
[![Go Report Card](https://goreportcard.com/badge/ory/fosite)](https://goreportcard.com/report/ory/fosite)
[![Join the chat at https://www.ory.sh/chat](https://img.shields.io/badge/join-chat-00cc99.svg)](https://www.ory.sh/chat)
**The security first OAuth2 & OpenID Connect framework for [Go](https://golang.org).**
Built simple, powerful and extensible. This library implements peer-reviewed [IETF RFC6749](https://tools.ietf.org/html/rfc6749),
counterfeits weaknesses covered in peer-reviewed [IETF RFC6819](https://tools.ietf.org/html/rfc6819) and countermeasures various database
attack scenarios, keeping your application safe when that hacker penetrates or leaks your database. OpenID Connect is
implemented according to [OpenID Connect Core 1.0 incorporating errata set 1](https://openid.net/specs/openid-connect-core-1_0.html) and
includes all flows: code, implicit, hybrid.
This library considered and implemented:
* [The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749)
* [OAuth 2.0 Multiple Response Type Encoding Practices](https://openid.net/specs/oauth-v2-multiple-response-types-1_0.html)
* [OAuth 2.0 Threat Model and Security Considerations](https://tools.ietf.org/html/rfc6819)
* [Proof Key for Code Exchange by OAuth Public Clients](https://tools.ietf.org/html/rfc7636)
* [OAuth 2.0 for Native Apps](https://tools.ietf.org/html/rfc8252)
* [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html)
OAuth2 and OpenID Connect are difficult protocols. If you want quick wins, we strongly encourage you to look at [Hydra](https://github.com/ory-am/hydra).
Hydra is a secure, high performance, cloud native OAuth2 and OpenID Connect service that integrates with every authentication method
imaginable and is built on top of Fosite.
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents**
- [Motivation](#motivation)
- [API Stability](#api-stability)
- [Example](#example)
- [A word on quality](#a-word-on-quality)
- [A word on security](#a-word-on-security)
- [A word on extensibility](#a-word-on-extensibility)
- [Installation](#installation)
- [Documentation](#documentation)
- [Scopes](#scopes)
- [`fosite.WildcardScopeStrategy`](#fositewildcardscopestrategy)
- [`fosite.HierarchicScopeStrategy`](#fositehierarchicscopestrategy)
- [Quickstart](#quickstart)
- [Code Examples](#code-examples)
- [Example Storage Implementation](#example-storage-implementation)
- [Extensible handlers](#extensible-handlers)
- [JWT Introspection](#jwt-introspection)
- [Contribute](#contribute)
- [Refresh mock objects](#refresh-mock-objects)
- [Hall of Fame](#hall-of-fame)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## Motivation
Fosite was written because our OAuth2 and OpenID Connect service [**Hydra**](https://github.com/ory-am/hydra)
required a secure and extensible OAuth2 library. We had to realize that nothing matching our requirements
was out there, so we decided to build it ourselves.
## API Stability
The core public API is almost stable as most changes will only touch the inner workings.
We strongly encourage vendoring fosite using [dep](https://github.com/golang/dep) or comparable tools.
## Example
The example does not have nice visuals but it should give you an idea of what you can do with Fosite and a few lines
of code.
![Authorize Code Grant](docs/authorize-code-grant.gif)
You can run this minimalistic example by doing
```
go get github.com/ory/fosite-example
cd $GOPATH/src/github.com/ory/fosite-example
dep ensure
go install github.com/ory/fosite-example
fosite-example
```
There should be a server listening on [localhost:3846](https://localhost:3846/). You can check out the example's
source code [here](https://github.com/ory/fosite-example/).
## A word on quality
We tried to set up as many tests as possible and test for as many cases covered in the RFCs as possible. But we are only
human. Please, feel free to add tests for the various cases defined in the OAuth2 RFCs 6749 and 6819 or any other cases that improve the tests.
**Everyone** writing an RFC conform test that breaks with the current implementation, will receive a place in the
[Hall of Fame](#hall-of-fame)!
## A word on security
Please be aware that Fosite only secures parts your server side security. You still need to secure your apps and clients, keep
your tokens safe, prevent CSRF attacks, ensure database security, use valid and strong TLS certificates and much more. If you need any help or advice feel free to contact our security staff through [our website](https://ory.am/)!
We have given the various specifications, especially [OAuth 2.0 Threat Model and Security Considerations](https://tools.ietf.org/html/rfc6819#section-5.1.5.3),
a very close look and included everything we thought was in the scope of this framework. Here is a complete list
of things we implemented in Fosite:
* [No Cleartext Storage of Credentials](https://tools.ietf.org/html/rfc6819#section-5.1.4.1.3)
* [Encryption of Credentials](https://tools.ietf.org/html/rfc6819#section-5.1.4.1.4)
* [Use Short Expiration Time](https://tools.ietf.org/html/rfc6819#section-5.1.5.3)
* [Limit Number of Usages or One-Time Usage](https://tools.ietf.org/html/rfc6819#section-5.1.5.4)
* [Bind Token to Client id](https://tools.ietf.org/html/rfc6819#section-5.1.5.8)
* [Automatic Revocation of Derived Tokens If Abuse Is Detected](https://tools.ietf.org/html/rfc6819#section-5.2.1.1)
* [Binding of Refresh Token to "client_id"](https://tools.ietf.org/html/rfc6819#section-5.2.2.2)
* [Refresh Token Rotation](https://tools.ietf.org/html/rfc6819#section-5.2.2.3)
* [Revocation of Refresh Tokens](https://tools.ietf.org/html/rfc6819#section-5.2.2.4)
* [Validate Pre-Registered "redirect_uri"](https://tools.ietf.org/html/rfc6819#section-5.2.3.5)
* [Binding of Authorization "code" to "client_id"](https://tools.ietf.org/html/rfc6819#section-5.2.4.4)
* [Binding of Authorization "code" to "redirect_uri"](https://tools.ietf.org/html/rfc6819#section-5.2.4.6)
* [Opaque access tokens](https://tools.ietf.org/html/rfc6749#section-1.4)
* [Opaque refresh tokens](https://tools.ietf.org/html/rfc6749#section-1.5)
* [Ensure Confidentiality of Requests](https://tools.ietf.org/html/rfc6819#section-5.1.1)
* [Use of Asymmetric Cryptography](https://tools.ietf.org/html/rfc6819#section-5.1.4.1.5)
Fosite ensures that redirect URIs use https **except localhost** but you need to implement
TLS for the token and auth endpoints yourself.
Additionally, we added these safeguards:
* **Enforcing random states:** Without a random-looking state or OpenID Connect nonce the request will fail.
* **Advanced Token Validation:** Tokens are layouted as `<key>.<signature>` where `<signature>` is created using HMAC-SHA256
using a global secret.
This is what a token can look like:
`/tgBeUhWlAT8tM8Bhmnx+Amf8rOYOUhrDi3pGzmjP7c=.BiV/Yhma+5moTP46anxMT6cWW8gz5R5vpC9RbpwSDdM=`
Sections below [Section 5](https://tools.ietf.org/html/rfc6819#section-5)
that are not covered in the list above should be reviewed by you. If you think that a specific section should be something
that is covered in Fosite, feel free to create an [issue](https://github.com/ory/fosite/issues). Please be
aware that OpenID Connect requires specific knowledge of the identity provider, which is why Fosite only implements core
requirements and most things must be implemented by you (for example prompt, max_age, ui_locales, id_token_hint, user authentication, session management, ...).
**It is strongly encouraged to use the handlers shipped with Fosite as they follow the specs and are well tested.**
## A word on extensibility
Fosite is extensible ... because OAuth2 is an extensible and flexible **framework**.
Fosite let's you register custom token and authorize endpoint handlers with the security that the requests
have been validated against the OAuth2 specs beforehand.
You can easily extend Fosite's capabilities. For example, if you want to provide OpenID Connect on top of your
OAuth2 stack, that's no problem. Or custom assertions, what ever you like and as long as it is secure. ;)
## Installation
[Go 1.11+](https://golang.org) must be installed on your system and it is required that you have set up your
GOPATH environment variable.
```
go get -u github.com/ory/fosite/...
```
We recommend to use [dep](https://github.com/golang/dep) to
mitigate compatibility breaks that come with new api versions.
## Documentation
There is an API documentation available at [godoc.org/ory/fosite](https://godoc.org/github.com/ory/fosite).
### Scopes
Fosite has three strategies for matching scopes. You can replace the default scope strategy if you need a custom
one by implementing `fosite.ScopeStrategy`.
Using the composer, setting a strategy is easy:
```go
import "github.com/ory/fosite/compose"
var config = &compose.Config{
ScopeStrategy: fosite.HierarchicScopeStrategy,
}
```
**Note:** To issue refresh tokens with any of the grants, you need to include the `offline` scope in the OAuth2 request. This can be modified by the `RefreshTokenScopes` compose configuration. When set to an empty array, _all_ grants will issue refresh tokens.
#### `fosite.WildcardScopeStrategy`
This is the default strategy, and the safest one. It is best explained by looking at some examples:
* `users.*` matches `users.read`
* `users.*` matches `users.read.foo`
* `users.read` matches `users.read`
* `users` does not match `users.read`
* `users.read.*` does not match `users.read`
* `users.*.*` does not match `users.read`
* `users.*.*` matches `users.read.own`
* `users.*.*` matches `users.read.own.other`
* `users.read.*` matches `users.read.own`
* `users.read.*` matches `users.read.own.other`
* `users.write.*` does not match `users.read.own`
* `users.*.bar` matches `users.baz.bar`
* `users.*.bar` does not `users.baz.baz.bar`
To request `users.*`, a client must have exactly `users.*` as granted scope.
#### `fosite.ExactScopeStrategy`
This strategy is searching only for exact matches. It returns true iff the scope is granted.
#### `fosite.HierarchicScopeStrategy`
This strategy is deprecated, use it with care. Again, it is best explained by looking at some examples:
* `users` matches `users`
* `users` matches `users.read`
* `users` matches `users.read.own`
* `users.read` matches `users.read`
* `users.read` matches `users.read.own`
* `users.read` does not match `users.write`
* `users.read` does not match `users.write.own`
### Quickstart
Instantiating fosite by hand can be painful. Therefore we created a few convenience helpers available through the [compose package](/compose).
It is strongly encouraged to use these well tested composers.
In this very basic example, we will instantiate fosite with all OpenID Connect and OAuth2 handlers enabled. Please refer
to the [example app](https://github.com/ory/fosite-example/) for more details.
This little code snippet sets up a full-blown OAuth2 and OpenID Connect example.
```go
import "github.com/ory/fosite"
import "github.com/ory/fosite/compose"
import "github.com/ory/fosite/storage"
// This is the example storage that contains:
// * an OAuth2 Client with id "my-client" and secret "foobar" capable of all oauth2 and open id connect grant and response types.
// * a User for the resource owner password credentials grant type with username "peter" and password "secret".
//
// You will most likely replace this with your own logic once you set up a real world application.
var storage = storage.NewExampleStore()
// This secret is being used to sign access and refresh tokens as well as
// authorization codes. It must be exactly 32 bytes long.
var secret = []byte("my super secret signing password")
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic("unable to create private key")
}
// check the api docs of compose.Config for further configuration options
var config = &compose.Config {
AccessTokenLifespan: time.Minute * 30,
// ...
}
var oauth2Provider = compose.ComposeAllEnabled(config, storage, secret, privateKey)
// The authorize endpoint is usually at "https://mydomain.com/oauth2/auth".
func authorizeHandlerFunc(rw http.ResponseWriter, req *http.Request) {
// This context will be passed to all methods. It doesn't fulfill a real purpose in the standard library but could be used
// to abort database lookups or similar things.
ctx := req.Context()
// Let's create an AuthorizeRequest object!
// It will analyze the request and extract important information like scopes, response type and others.
ar, err := oauth2Provider.NewAuthorizeRequest(ctx, req)
if err != nil {
oauth2Provider.WriteAuthorizeError(rw, ar, err)
return
}
// Normally, this would be the place where you would check if the user is logged in and gives his consent.
// We're simplifying things and just checking if the request includes a valid username and password
if req.Form.Get("username") != "peter" {
rw.Header().Set("Content-Type", "text/html; charset=utf-8")
rw.Write([]byte(`<h1>Login page</h1>`))
rw.Write([]byte(`
<p>Howdy! This is the log in page. For this example, it is enough to supply the username.</p>
<form method="post">
<input type="text" name="username" /> <small>try peter</small><br>
<input type="submit">
</form>
`))
return
}
// Now that the user is authorized, we set up a session. When validating / looking up tokens, we additionally get
// the session. You can store anything you want in it.
// The session will be persisted by the store and made available when e.g. validating tokens or handling token endpoint requests.
// The default OAuth2 and OpenID Connect handlers require the session to implement a few methods. Apart from that, the
// session struct can be anything you want it to be.
mySessionData := &fosite.DefaultSession{
Username: req.Form.Get("username"),
}
// It's also wise to check the requested scopes, e.g.:
// if authorizeRequest.GetScopes().Has("admin") {
// http.Error(rw, "you're not allowed to do that", http.StatusForbidden)
// return
// }
// Now we need to get a response. This is the place where the AuthorizeEndpointHandlers kick in and start processing the request.
// NewAuthorizeResponse is capable of running multiple response type handlers which in turn enables this library
// to support open id connect.
response, err := oauth2Provider.NewAuthorizeResponse(ctx, ar, mySessionData)
if err != nil {
oauth2Provider.WriteAuthorizeError(rw, ar, err)
return
}
// Awesome, now we redirect back to the client redirect uri and pass along an authorize code
oauth2Provider.WriteAuthorizeResponse(rw, ar, response)
}
// The token endpoint is usually at "https://mydomain.com/oauth2/token"
func tokenHandlerFunc(rw http.ResponseWriter, req *http.Request) {
ctx := req.Context()
mySessionData := new(fosite.DefaultSession)
// This will create an access request object and iterate through the registered TokenEndpointHandlers to validate the request.
accessRequest, err := oauth2Provider.NewAccessRequest(ctx, req, mySessionData)
if err != nil {
oauth2Provider.WriteAccessError(rw, accessRequest, err)
return
}
if mySessionData.Username == "super-admin-guy" {
// do something...
}
// Next we create a response for the access request. Again, we iterate through the TokenEndpointHandlers
// and aggregate the result in response.
response, err := oauth2Provider.NewAccessResponse(ctx, accessRequest)
if err != nil {
oauth2Provider.WriteAccessError(rw, accessRequest, err)
return
}
// All done, send the response.
oauth2Provider.WriteAccessResponse(rw, accessRequest, response)
// The client has a valid access token now
}
func someResourceProviderHandlerFunc(rw http.ResponseWriter, req *http.Request) {
ctx := req.Context()
requiredScope := "blogposts.create"
_, ar, err := oauth2Provider.IntrospectToken(ctx, fosite.AccessTokenFromRequest(req), fosite.AccessToken, new(fosite.DefaultSession), requiredScope)
if err != nil {
// ...
}
// If no error occurred the token + scope is valid and you have access to:
// ar.GetClient().GetID(), ar.GetGrantedScopes(), ar.GetScopes(), ar.GetSession().UserID, ar.GetRequestedAt(), ...
}
```
### Code Examples
Fosite provides integration tests as well as a http server example:
* Fosite ships with an example app that runs in your browser: [Example app](https://github.com/ory/fosite-example/).
* If you want to check out how to enable specific handlers, check out the [integration tests](integration/).
If you have working examples yourself, please share them with us!
### Example Storage Implementation
Fosite does not ship a storage implementation. This is intended, because requirements vary with every environment.
You can find a reference implementation at [storage/memory.go](storage/memory.go).
This storage fulfills requirements from all OAuth2 and OpenID Connect handlers.
### Extensible handlers
OAuth2 is a framework. Fosite mimics this behaviour by enabling you to replace existing or create new OAuth2 handlers.
Of course, fosite ships handlers for all OAuth2 and OpenID Connect flows.
* **[Fosite OAuth2 Core Handlers](handler/oauth2)** implement the [Client Credentials Grant](https://tools.ietf.org/html/rfc6749#section-4.4),
[Resource Owner Password Credentials Grant](https://tools.ietf.org/html/rfc6749#section-4.3),
[Implicit Grant](https://tools.ietf.org/html/rfc6749#section-4.2),
[Authorization Code Grant](https://tools.ietf.org/html/rfc6749#section-4.1),
[Refresh Token Grant](https://tools.ietf.org/html/rfc6749#section-6)
* **[Fosite OpenID Connect Handlers](handler/openid)** implement the
[Authentication using the Authorization Code Flow](http://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth),
[Authentication using the Implicit Flow](http://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth),
[Authentication using the Hybrid Flow](http://openid.net/specs/openid-connect-core-1_0.html#HybridFlowAuth)
This section is missing documentation and we welcome any contributions in that direction.
### JWT Introspection
Please note that when using the OAuth2StatelessJWTIntrospectionFactory access token revocation is not possible.
## Contribute
You need git and golang installed on your system.
```
go get -d github.com/ory/fosite
cd $GOPATH/src/github.com/ory/fosite
git status
git remote add myfork <url-to-your-fork>
go test ./..
```
Simple, right? Now you are ready to go! Make sure to run `go test ./...` often, detecting problems with your code
rather sooner than later. Please read [CONTRIBUTE.md] before creating pull requests and issues.
### Refresh mock objects
Run `./generate-mocks.sh` in fosite's root directory or run the contents of [generate-mocks.sh] in a shell.
## Hall of Fame
This place is reserved for the fearless bug hunters, reviewers and contributors (alphabetical order).
* [agtorre](https://github.com/agtorre):
[contributions](https://github.com/ory/fosite/issues?q=author%3Aagtorre),
[participations](https://github.com/ory/fosite/issues?q=commenter%3Aagtorre).
* [danielchatfield](https://github.com/danielchatfield):
[contributions](https://github.com/ory/fosite/issues?q=author%3Adanielchatfield),
[participations](https://github.com/ory/fosite/issues?q=commenter%3Adanielchatfield).
* [leetal](https://github.com/leetal):
[contributions](https://github.com/ory/fosite/issues?q=author%3Aleetal),
[participations](https://github.com/ory/fosite/issues?q=commenter%3Aleetal).
* [jrossiter](https://github.com/jrossiter):
[contributions](https://github.com/ory/fosite/issues?q=author%3Ajrossiter),
[participations](https://github.com/ory/fosite/issues?q=commenter%3Ajrossiter).
* [jrossiter](https://github.com/jrossiter):
[contributions](https://github.com/ory/fosite/issues?q=author%3Ajrossiter),
[participations](https://github.com/ory/fosite/issues?q=commenter%3Ajrossiter).
* [danilobuerger](https://github.com/danilobuerger):
[contributions](https://github.com/ory/fosite/issues?q=author%3Adanilobuerger),
[participations](https://github.com/ory/fosite/issues?q=commenter%3Adanilobuerger).
Find out more about the [author](https://aeneas.io/) of Fosite and Hydra, and the
[Ory Company](https://ory.am/).

38
vendor/github.com/ory/fosite/SECURITY.md generated vendored Normal file
View File

@ -0,0 +1,38 @@
<!--
Thank you for contributing changes to this document! Because we use a central repository
to synchronize this file across all our repositories, make sure to make your edits
in the correct file, which you can find here:
https://github.com/ory/meta/blob/master/templates/repository/SECURITY.md
-->
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
- [Security Policy](#security-policy)
- [Supported Versions](#supported-versions)
- [Reporting a Vulnerability](#reporting-a-vulnerability)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
# Security Policy
## Supported Versions
We release patches for security vulnerabilities. Which versions are eligible
receiving such patches depend on the CVSS v3.0 Rating:
| CVSS v3.0 | Supported Versions |
| --------- | ----------------------------------------- |
| 9.0-10.0 | Releases within the previous three months |
| 4.0-8.9 | Most recent release |
## Reporting a Vulnerability
Please report (suspected) security vulnerabilities to
**[security@ory.sh](mailto:security@ory.sh)**. You will receive a response from
us within 48 hours. If the issue is confirmed, we will release a patch as soon
as possible depending on complexity but historically within a few days.

50
vendor/github.com/ory/fosite/access_error.go generated vendored Normal file
View File

@ -0,0 +1,50 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package fosite
import (
"encoding/json"
"fmt"
"net/http"
)
func (f *Fosite) WriteAccessError(rw http.ResponseWriter, _ AccessRequester, err error) {
f.writeJsonError(rw, err)
}
func (f *Fosite) writeJsonError(rw http.ResponseWriter, err error) {
rw.Header().Set("Content-Type", "application/json;charset=UTF-8")
rfcerr := ErrorToRFC6749Error(err)
if !f.SendDebugMessagesToClients {
rfcerr.Debug = ""
}
js, err := json.Marshal(rfcerr)
if err != nil {
http.Error(rw, fmt.Sprintf(`{"error": "%s"}`, err.Error()), http.StatusInternalServerError)
return
}
rw.WriteHeader(rfcerr.Code)
rw.Write(js)
}

43
vendor/github.com/ory/fosite/access_request.go generated vendored Normal file
View File

@ -0,0 +1,43 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package fosite
type AccessRequest struct {
GrantTypes Arguments `json:"grantTypes" gorethink:"grantTypes"`
HandledGrantType Arguments `json:"handledGrantType" gorethink:"handledGrantType"`
Request
}
func NewAccessRequest(session Session) *AccessRequest {
r := &AccessRequest{
GrantTypes: Arguments{},
HandledGrantType: Arguments{},
Request: *NewRequest(),
}
r.Session = session
return r
}
func (a *AccessRequest) GetGrantTypes() Arguments {
return a.GrantTypes
}

102
vendor/github.com/ory/fosite/access_request_handler.go generated vendored Normal file
View File

@ -0,0 +1,102 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package fosite
import (
"context"
"net/http"
"strings"
"github.com/pkg/errors"
)
// Implements
// * https://tools.ietf.org/html/rfc6749#section-2.3.1
// Clients in possession of a client password MAY use the HTTP Basic
// authentication scheme as defined in [RFC2617] to authenticate with
// the authorization server. The client identifier is encoded using the
// "application/x-www-form-urlencoded" encoding algorithm per
// Appendix B, and the encoded value is used as the username; the client
// password is encoded using the same algorithm and used as the
// password. The authorization server MUST support the HTTP Basic
// authentication scheme for authenticating clients that were issued a
// client password.
// Including the client credentials in the request-body using the two
// parameters is NOT RECOMMENDED and SHOULD be limited to clients unable
// to directly utilize the HTTP Basic authentication scheme (or other
// password-based HTTP authentication schemes). The parameters can only
// be transmitted in the request-body and MUST NOT be included in the
// request URI.
// * https://tools.ietf.org/html/rfc6749#section-3.2.1
// - Confidential clients or other clients issued client credentials MUST
// authenticate with the authorization server as described in
// Section 2.3 when making requests to the token endpoint.
// - If the client type is confidential or the client was issued client
// credentials (or assigned other authentication requirements), the
// client MUST authenticate with the authorization server as described
// in Section 3.2.1.
func (f *Fosite) NewAccessRequest(ctx context.Context, r *http.Request, session Session) (AccessRequester, error) {
var err error
accessRequest := NewAccessRequest(session)
if r.Method != "POST" {
return accessRequest, errors.WithStack(ErrInvalidRequest.WithHintf("HTTP method is \"%s\", expected \"POST\".", r.Method))
} else if err := r.ParseMultipartForm(1 << 20); err != nil && err != http.ErrNotMultipart {
return accessRequest, errors.WithStack(ErrInvalidRequest.WithHint("Unable to parse HTTP body, make sure to send a properly formatted form request body.").WithDebug(err.Error()))
} else if len(r.PostForm) == 0 {
return accessRequest, errors.WithStack(ErrInvalidRequest.WithHint("The POST body can not be empty."))
}
accessRequest.Form = r.PostForm
if session == nil {
return accessRequest, errors.New("Session must not be nil")
}
accessRequest.SetRequestedScopes(RemoveEmpty(strings.Split(r.PostForm.Get("scope"), " ")))
accessRequest.SetRequestedAudience(RemoveEmpty(strings.Split(r.PostForm.Get("audience"), " ")))
accessRequest.GrantTypes = RemoveEmpty(strings.Split(r.PostForm.Get("grant_type"), " "))
if len(accessRequest.GrantTypes) < 1 {
return accessRequest, errors.WithStack(ErrInvalidRequest.WithHint(`Request parameter "grant_type"" is missing`))
}
client, err := f.AuthenticateClient(ctx, r, r.PostForm)
if err != nil {
return accessRequest, err
}
accessRequest.Client = client
var found bool = false
for _, loader := range f.TokenEndpointHandlers {
if err := loader.HandleTokenEndpointRequest(ctx, accessRequest); err == nil {
found = true
} else if errors.Cause(err).Error() == ErrUnknownRequest.Error() {
// do nothing
} else if err != nil {
return accessRequest, err
}
}
if !found {
return nil, errors.WithStack(ErrInvalidRequest)
}
return accessRequest, nil
}

77
vendor/github.com/ory/fosite/access_response.go generated vendored Normal file
View File

@ -0,0 +1,77 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package fosite
import (
"strings"
"time"
)
func NewAccessResponse() *AccessResponse {
return &AccessResponse{
Extra: map[string]interface{}{},
}
}
type AccessResponse struct {
Extra map[string]interface{}
AccessToken string
TokenType string
}
func (a *AccessResponse) SetScopes(scopes Arguments) {
a.SetExtra("scope", strings.Join(scopes, " "))
}
func (a *AccessResponse) SetExpiresIn(expiresIn time.Duration) {
a.SetExtra("expires_in", int64(expiresIn/time.Second))
}
func (a *AccessResponse) SetExtra(key string, value interface{}) {
a.Extra[key] = value
}
func (a *AccessResponse) GetExtra(key string) interface{} {
return a.Extra[key]
}
func (a *AccessResponse) SetAccessToken(token string) {
a.AccessToken = token
}
func (a *AccessResponse) SetTokenType(name string) {
a.TokenType = name
}
func (a *AccessResponse) GetAccessToken() string {
return a.AccessToken
}
func (a *AccessResponse) GetTokenType() string {
return a.TokenType
}
func (a *AccessResponse) ToMap() map[string]interface{} {
a.Extra["access_token"] = a.GetAccessToken()
a.Extra["token_type"] = a.GetTokenType()
return a.Extra
}

48
vendor/github.com/ory/fosite/access_response_writer.go generated vendored Normal file
View File

@ -0,0 +1,48 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package fosite
import (
"context"
"github.com/pkg/errors"
)
func (f *Fosite) NewAccessResponse(ctx context.Context, requester AccessRequester) (AccessResponder, error) {
var err error
var tk TokenEndpointHandler
response := NewAccessResponse()
for _, tk = range f.TokenEndpointHandlers {
if err = tk.PopulateTokenEndpointResponse(ctx, requester, response); err == nil {
} else if errors.Cause(err).Error() == ErrUnknownRequest.Error() {
} else if err != nil {
return nil, err
}
}
if response.GetAccessToken() == "" || response.GetTokenType() == "" {
return nil, errors.WithStack(ErrServerError.WithHint("An internal server occurred while trying to complete the request.").WithDebug("Access token or token type not set by TokenEndpointHandlers."))
}
return response, nil
}

42
vendor/github.com/ory/fosite/access_write.go generated vendored Normal file
View File

@ -0,0 +1,42 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package fosite
import (
"encoding/json"
"net/http"
)
func (f *Fosite) WriteAccessResponse(rw http.ResponseWriter, requester AccessRequester, responder AccessResponder) {
js, err := json.Marshal(responder.ToMap())
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
rw.Header().Set("Content-Type", "application/json;charset=UTF-8")
rw.Header().Set("Cache-Control", "no-store")
rw.Header().Set("Pragma", "no-cache")
rw.WriteHeader(http.StatusOK)
rw.Write(js)
}

98
vendor/github.com/ory/fosite/arguments.go generated vendored Normal file
View File

@ -0,0 +1,98 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package fosite
import "strings"
type Arguments []string
// Matches performs an case-insensitive, out-of-order check that the items
// provided exist and equal all of the args in arguments.
// Note:
// - Providing a list that includes duplicate string-case items will return not
// matched.
func (r Arguments) Matches(items ...string) bool {
if len(r) != len(items) {
return false
}
found := make(map[string]bool)
for _, item := range items {
if !StringInSlice(item, r) {
return false
}
found[item] = true
}
return len(found) == len(r)
}
// Has checks, in a case-insensitive manner, that all of the items
// provided exists in arguments.
func (r Arguments) Has(items ...string) bool {
for _, item := range items {
if !StringInSlice(item, r) {
return false
}
}
return true
}
// HasOneOf checks, in a case-insensitive manner, that one of the items
// provided exists in arguments.
func (r Arguments) HasOneOf(items ...string) bool {
for _, item := range items {
if StringInSlice(item, r) {
return true
}
}
return false
}
// Deprecated: Use ExactOne, Matches or MatchesExact
func (r Arguments) Exact(name string) bool {
return name == strings.Join(r, " ")
}
// ExactOne checks, by string case, that a single argument equals the provided
// string.
func (r Arguments) ExactOne(name string) bool {
return len(r) == 1 && r[0] == name
}
// MatchesExact checks, by order and string case, that the items provided equal
// those in arguments.
func (r Arguments) MatchesExact(items ...string) bool {
if len(r) != len(items) {
return false
}
for i, item := range items {
if item != r[i] {
return false
}
}
return true
}

60
vendor/github.com/ory/fosite/audience_strategy.go generated vendored Normal file
View File

@ -0,0 +1,60 @@
package fosite
import (
"net/http"
"net/url"
"strings"
"github.com/pkg/errors"
"github.com/ory/go-convenience/stringsx"
)
type AudienceMatchingStrategy func(haystack []string, needle []string) error
func DefaultAudienceMatchingStrategy(haystack []string, needle []string) error {
if len(needle) == 0 {
return nil
}
for _, n := range needle {
nu, err := url.Parse(n)
if err != nil {
return errors.WithStack(ErrInvalidRequest.WithHintf(`Unable to parse requested audience "%s".`, n).WithDebug(err.Error()))
}
var found bool
for _, h := range haystack {
hu, err := url.Parse(h)
if err != nil {
return errors.WithStack(ErrInvalidRequest.WithHintf(`Unable to parse whitelisted audience "%s".`, h).WithDebug(err.Error()))
}
allowedPath := strings.TrimRight(hu.Path, "/")
if nu.Scheme == hu.Scheme &&
nu.Host == hu.Host &&
(nu.Path == hu.Path ||
nu.Path == allowedPath ||
len(nu.Path) > len(allowedPath) && strings.TrimRight(nu.Path[:len(allowedPath)+1], "/")+"/" == allowedPath+"/") {
found = true
}
}
if !found {
return errors.WithStack(ErrInvalidRequest.WithHintf(`Requested audience "%s" has not been whitelisted by the OAuth 2.0 Client.`, n))
}
}
return nil
}
func (f *Fosite) validateAuthorizeAudience(r *http.Request, request *AuthorizeRequest) error {
audience := stringsx.Splitx(request.Form.Get("audience"), " ")
if err := f.AudienceMatchingStrategy(request.Client.GetAudience(), audience); err != nil {
return err
}
request.SetRequestedAudience(Arguments(audience))
return nil
}

77
vendor/github.com/ory/fosite/authorize_error.go generated vendored Normal file
View File

@ -0,0 +1,77 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package fosite
import (
"encoding/json"
"net/http"
"net/url"
"github.com/pkg/errors"
)
func (f *Fosite) WriteAuthorizeError(rw http.ResponseWriter, ar AuthorizeRequester, err error) {
rfcerr := ErrorToRFC6749Error(err)
if !ar.IsRedirectURIValid() {
if !f.SendDebugMessagesToClients {
rfcerr.Debug = ""
}
js, err := json.MarshalIndent(rfcerr, "", "\t")
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
rw.Header().Set("Content-Type", "application/json")
rw.WriteHeader(rfcerr.Code)
rw.Write(js)
return
}
redirectURI := ar.GetRedirectURI()
query := url.Values{}
query.Add("error", rfcerr.Name)
query.Add("error_description", rfcerr.Description)
query.Add("state", ar.GetState())
if f.SendDebugMessagesToClients && rfcerr.Debug != "" {
query.Add("error_debug", rfcerr.Debug)
}
if rfcerr.Hint != "" {
query.Add("error_hint", rfcerr.Hint)
}
if !(len(ar.GetResponseTypes()) == 0 || ar.GetResponseTypes().ExactOne("code")) && errors.Cause(err) != ErrUnsupportedResponseType {
redirectURI.Fragment = query.Encode()
} else {
for key, values := range redirectURI.Query() {
for _, value := range values {
query.Add(key, value)
}
}
redirectURI.RawQuery = query.Encode()
}
rw.Header().Add("Location", redirectURI.String())
rw.WriteHeader(http.StatusFound)
}

181
vendor/github.com/ory/fosite/authorize_helper.go generated vendored Normal file
View File

@ -0,0 +1,181 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package fosite
import (
"net/url"
"regexp"
"strings"
"github.com/asaskevich/govalidator"
"github.com/pkg/errors"
)
// GetRedirectURIFromRequestValues extracts the redirect_uri from values but does not do any sort of validation.
//
// Considered specifications
// * https://tools.ietf.org/html/rfc6749#section-3.1
// The endpoint URI MAY include an
// "application/x-www-form-urlencoded" formatted (per Appendix B) query
// component ([RFC3986] Section 3.4), which MUST be retained when adding
// additional query parameters.
func GetRedirectURIFromRequestValues(values url.Values) (string, error) {
// rfc6749 3.1. Authorization Endpoint
// The endpoint URI MAY include an "application/x-www-form-urlencoded" formatted (per Appendix B) query component
redirectURI, err := url.QueryUnescape(values.Get("redirect_uri"))
if err != nil {
return "", errors.WithStack(ErrInvalidRequest.WithHint(`The "redirect_uri" parameter is malformed or missing.`).WithDebug(err.Error()))
}
return redirectURI, nil
}
// MatchRedirectURIWithClientRedirectURIs if the given uri is a registered redirect uri. Does not perform
// uri validation.
//
// Considered specifications
// * https://tools.ietf.org/html/rfc6749#section-3.1.2.3
// If multiple redirection URIs have been registered, if only part of
// the redirection URI has been registered, or if no redirection URI has
// been registered, the client MUST include a redirection URI with the
// authorization request using the "redirect_uri" request parameter.
//
// When a redirection URI is included in an authorization request, the
// authorization server MUST compare and match the value received
// against at least one of the registered redirection URIs (or URI
// components) as defined in [RFC3986] Section 6, if any redirection
// URIs were registered. If the client registration included the full
// redirection URI, the authorization server MUST compare the two URIs
// using simple string comparison as defined in [RFC3986] Section 6.2.1.
//
// * https://tools.ietf.org/html/rfc6819#section-4.4.1.7
// * The authorization server may also enforce the usage and validation
// of pre-registered redirect URIs (see Section 5.2.3.5). This will
// allow for early recognition of authorization "code" disclosure to
// counterfeit clients.
// * The attacker will need to use another redirect URI for its
// authorization process rather than the target web site because it
// needs to intercept the flow. So, if the authorization server
// associates the authorization "code" with the redirect URI of a
// particular end-user authorization and validates this redirect URI
// with the redirect URI passed to the token's endpoint, such an
// attack is detected (see Section 5.2.4.5).
func MatchRedirectURIWithClientRedirectURIs(rawurl string, client Client) (*url.URL, error) {
if rawurl == "" && len(client.GetRedirectURIs()) == 1 {
if redirectURIFromClient, err := url.Parse(client.GetRedirectURIs()[0]); err == nil && IsValidRedirectURI(redirectURIFromClient) {
// If no redirect_uri was given and the client has exactly one valid redirect_uri registered, use that instead
return redirectURIFromClient, nil
}
} else if rawurl != "" && isMatchingRedirectURI(rawurl, client.GetRedirectURIs()) {
// If a redirect_uri was given and the clients knows it (simple string comparison!)
// return it.
if parsed, err := url.Parse(rawurl); err == nil && IsValidRedirectURI(parsed) {
// If no redirect_uri was given and the client has exactly one valid redirect_uri registered, use that instead
return parsed, nil
}
}
return nil, errors.WithStack(ErrInvalidRequest.WithHint(`The "redirect_uri" parameter does not match any of the OAuth 2.0 Client's pre-registered redirect urls.`))
}
// Match a requested redirect URI against a pool of registered client URIs
//
// Test a given redirect URI against a pool of URIs provided by a registered client.
// If the OAuth 2.0 Client has loopback URIs registered either an IPv4 URI http://127.0.0.1 or
// an IPv6 URI http://[::1] a client is allowed to request a dynamic port and the server MUST accept
// it as a valid redirection uri.
//
// https://tools.ietf.org/html/rfc8252#section-7.3
// Native apps that are able to open a port on the loopback network
// interface without needing special permissions (typically, those on
// desktop operating systems) can use the loopback interface to receive
// the OAuth redirect.
//
// Loopback redirect URIs use the "http" scheme and are constructed with
// the loopback IP literal and whatever port the client is listening on.
func isMatchingRedirectURI(uri string, haystack []string) bool {
requested, err := url.Parse(uri)
if err != nil {
return false
}
for _, b := range haystack {
if strings.ToLower(b) == strings.ToLower(uri) || isLoopbackURI(requested, b) {
return true
}
}
return false
}
func isLoopbackURI(requested *url.URL, registeredURI string) bool {
registered, err := url.Parse(registeredURI)
if err != nil {
return false
}
if registered.Scheme != "http" || !isLoopbackAddress(registered.Host) {
return false
}
if requested.Scheme == "http" && isLoopbackAddress(requested.Host) && registered.Path == requested.Path {
return true
}
return false
}
// Check if address is either an IPv4 loopback or an IPv6 loopback-
// An optional port is ignored
func isLoopbackAddress(address string) bool {
match, _ := regexp.MatchString("^(127.0.0.1|\\[::1\\])(:?)(\\d*)$", address)
return match
}
// IsValidRedirectURI validates a redirect_uri as specified in:
//
// * https://tools.ietf.org/html/rfc6749#section-3.1.2
// * The redirection endpoint URI MUST be an absolute URI as defined by [RFC3986] Section 4.3.
// * The endpoint URI MUST NOT include a fragment component.
// * https://tools.ietf.org/html/rfc3986#section-4.3
// absolute-URI = scheme ":" hier-part [ "?" query ]
// * https://tools.ietf.org/html/rfc6819#section-5.1.1
func IsValidRedirectURI(redirectURI *url.URL) bool {
// We need to explicitly check for a scheme
if !govalidator.IsRequestURL(redirectURI.String()) {
return false
}
if redirectURI.Fragment != "" {
// "The endpoint URI MUST NOT include a fragment component."
return false
}
return true
}
func IsRedirectURISecure(redirectURI *url.URL) bool {
return !(redirectURI.Scheme == "http" && !IsLocalhost(redirectURI))
}
func IsLocalhost(redirectURI *url.URL) bool {
hn := redirectURI.Hostname()
return strings.HasSuffix(hn, ".localhost") || hn == "127.0.0.1" || hn == "localhost"
}

88
vendor/github.com/ory/fosite/authorize_request.go generated vendored Normal file
View File

@ -0,0 +1,88 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package fosite
import (
"net/url"
)
// AuthorizeRequest is an implementation of AuthorizeRequester
type AuthorizeRequest struct {
ResponseTypes Arguments `json:"responseTypes" gorethink:"responseTypes"`
RedirectURI *url.URL `json:"redirectUri" gorethink:"redirectUri"`
State string `json:"state" gorethink:"state"`
HandledResponseTypes Arguments `json:"handledResponseTypes" gorethink:"handledResponseTypes"`
Request
}
func NewAuthorizeRequest() *AuthorizeRequest {
return &AuthorizeRequest{
ResponseTypes: Arguments{},
RedirectURI: &url.URL{},
HandledResponseTypes: Arguments{},
Request: *NewRequest(),
}
}
func (d *AuthorizeRequest) IsRedirectURIValid() bool {
if d.GetRedirectURI() == nil {
return false
}
raw := d.GetRedirectURI().String()
if d.GetClient() == nil {
return false
}
redirectURI, err := MatchRedirectURIWithClientRedirectURIs(raw, d.GetClient())
if err != nil {
return false
}
return IsValidRedirectURI(redirectURI)
}
func (d *AuthorizeRequest) GetResponseTypes() Arguments {
return d.ResponseTypes
}
func (d *AuthorizeRequest) GetState() string {
return d.State
}
func (d *AuthorizeRequest) GetRedirectURI() *url.URL {
return d.RedirectURI
}
func (d *AuthorizeRequest) SetResponseTypeHandled(name string) {
d.HandledResponseTypes = append(d.HandledResponseTypes, name)
}
func (d *AuthorizeRequest) DidHandleAllResponseTypes() bool {
for _, rt := range d.ResponseTypes {
if !d.HandledResponseTypes.Has(rt) {
return false
}
}
return len(d.ResponseTypes) > 0
}

View File

@ -0,0 +1,276 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package fosite
import (
"context"
"fmt"
"io/ioutil"
"net/http"
"strings"
jwt "github.com/dgrijalva/jwt-go"
"github.com/pkg/errors"
"github.com/ory/go-convenience/stringslice"
"github.com/ory/go-convenience/stringsx"
)
func (f *Fosite) authorizeRequestParametersFromOpenIDConnectRequest(request *AuthorizeRequest) error {
var scope Arguments = stringsx.Splitx(request.Form.Get("scope"), " ")
// Even if a scope parameter is present in the Request Object value, a scope parameter MUST always be passed using
// the OAuth 2.0 request syntax containing the openid scope value to indicate to the underlying OAuth 2.0 logic that this is an OpenID Connect request.
// Source: http://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth
if !scope.Has("openid") {
return nil
}
if len(request.Form.Get("request")+request.Form.Get("request_uri")) == 0 {
return nil
} else if len(request.Form.Get("request")) > 0 && len(request.Form.Get("request_uri")) > 0 {
return errors.WithStack(ErrInvalidRequest.WithHint(`OpenID Connect parameters "request" and "request_uri" were both given, but you can use at most one.`))
}
oidcClient, ok := request.Client.(OpenIDConnectClient)
if !ok {
if len(request.Form.Get("request_uri")) > 0 {
return errors.WithStack(ErrRequestURINotSupported.WithHint(`OpenID Connect "request_uri" context was given, but the OAuth 2.0 Client does not implement advanced OpenID Connect capabilities.`))
}
return errors.WithStack(ErrRequestNotSupported.WithHint(`OpenID Connect "request" context was given, but the OAuth 2.0 Client does not implement advanced OpenID Connect capabilities.`))
}
if oidcClient.GetJSONWebKeys() == nil && len(oidcClient.GetJSONWebKeysURI()) == 0 {
return errors.WithStack(ErrInvalidRequest.WithHint(`OpenID Connect "request" or "request_uri" context was given, but the OAuth 2.0 Client does not have any JSON Web Keys registered.`))
}
assertion := request.Form.Get("request")
if location := request.Form.Get("request_uri"); len(location) > 0 {
if !stringslice.Has(oidcClient.GetRequestURIs(), location) {
return errors.WithStack(ErrInvalidRequestURI.WithHint(fmt.Sprintf("Request URI \"%s\" is not whitelisted by the OAuth 2.0 Client.", location)))
}
hc := f.HTTPClient
if hc == nil {
hc = http.DefaultClient
}
response, err := hc.Get(location)
if err != nil {
return errors.WithStack(ErrInvalidRequestURI.WithHintf(`Unable to fetch OpenID Connect request parameters from "request_uri" because %s.`, err.Error()))
}
defer response.Body.Close()
if response.StatusCode != http.StatusOK {
return errors.WithStack(ErrInvalidRequestURI.WithHintf(`Unable to fetch OpenID Connect request parameters from "request_uri" because status code "%d" was expected, but got "%d".`, http.StatusOK, response.StatusCode))
}
body, err := ioutil.ReadAll(response.Body)
if err != nil {
return errors.WithStack(ErrInvalidRequestURI.WithHintf(`Unable to fetch OpenID Connect request parameters from "request_uri" because error %s occurred during body parsing.`, err))
}
assertion = string(body)
}
token, err := jwt.ParseWithClaims(assertion, new(jwt.MapClaims), func(t *jwt.Token) (interface{}, error) {
if oidcClient.GetRequestObjectSigningAlgorithm() != fmt.Sprintf("%s", t.Header["alg"]) {
return nil, errors.WithStack(ErrInvalidRequestObject.WithHintf(`The request object uses signing algorithm %s, but the requested OAuth 2.0 Client enforces signing algorithm %s.`, t.Header["alg"], oidcClient.GetRequestObjectSigningAlgorithm()))
}
if t.Method == jwt.SigningMethodNone {
return jwt.UnsafeAllowNoneSignatureType, nil
}
switch t.Method.(type) {
case *jwt.SigningMethodRSA:
key, err := f.findClientPublicJWK(oidcClient, t, true)
if err != nil {
return nil, errors.WithStack(ErrInvalidRequestObject.WithHintf("Unable to retrieve RSA signing key from OAuth 2.0 Client because %s.", err))
}
return key, nil
case *jwt.SigningMethodECDSA:
key, err := f.findClientPublicJWK(oidcClient, t, false)
if err != nil {
return nil, errors.WithStack(ErrInvalidRequestObject.WithHintf("Unable to retrieve ECDSA signing key from OAuth 2.0 Client because %s.", err))
}
return key, nil
case *jwt.SigningMethodRSAPSS:
key, err := f.findClientPublicJWK(oidcClient, t, true)
if err != nil {
return nil, errors.WithStack(ErrInvalidRequestObject.WithHintf("Unable to retrieve RSA signing key from OAuth 2.0 Client because %s.", err))
}
return key, nil
default:
return nil, errors.WithStack(ErrInvalidRequestObject.WithHintf(`This request object uses unsupported signing algorithm "%s"."`, t.Header["alg"]))
}
})
if err != nil {
// Do not re-process already enhanced errors
if e, ok := errors.Cause(err).(*jwt.ValidationError); ok {
if e.Inner != nil {
return e.Inner
}
return errors.WithStack(ErrInvalidRequestObject.WithHintf("Unable to verify the request object's signature.").WithDebug(err.Error()))
}
return err
} else if err := token.Claims.Valid(); err != nil {
return errors.WithStack(ErrInvalidRequestObject.WithHint("Unable to verify the request object because its claims could not be validated, check if the expiry time is set correctly.").WithDebug(err.Error()))
}
claims, ok := token.Claims.(*jwt.MapClaims)
if !ok {
return errors.WithStack(ErrInvalidRequestObject.WithHint("Unable to type assert claims from request object.").WithDebugf(`Got claims of type %T but expected type "*jwt.MapClaims".`, token.Claims))
}
for k, v := range *claims {
request.Form.Set(k, fmt.Sprintf("%s", v))
}
claimScope := stringsx.Splitx(request.Form.Get("scope"), " ")
for _, s := range scope {
if !stringslice.Has(claimScope, s) {
claimScope = append(claimScope, s)
}
}
request.Form.Set("scope", strings.Join(claimScope, " "))
return nil
}
func (f *Fosite) validateAuthorizeRedirectURI(r *http.Request, request *AuthorizeRequest) error {
// Fetch redirect URI from request
rawRedirURI, err := GetRedirectURIFromRequestValues(request.Form)
if err != nil {
return err
}
// Validate redirect uri
redirectURI, err := MatchRedirectURIWithClientRedirectURIs(rawRedirURI, request.Client)
if err != nil {
return err
} else if !IsValidRedirectURI(redirectURI) {
return errors.WithStack(ErrInvalidRequest.WithHintf(`The redirect URI "%s" contains an illegal character (for example #) or is otherwise invalid.`, redirectURI))
}
request.RedirectURI = redirectURI
return nil
}
func (f *Fosite) validateAuthorizeScope(r *http.Request, request *AuthorizeRequest) error {
scope := stringsx.Splitx(request.Form.Get("scope"), " ")
for _, permission := range scope {
if !f.ScopeStrategy(request.Client.GetScopes(), permission) {
return errors.WithStack(ErrInvalidScope.WithHintf(`The OAuth 2.0 Client is not allowed to request scope "%s".`, permission))
}
}
request.SetRequestedScopes(scope)
return nil
}
func (f *Fosite) validateResponseTypes(r *http.Request, request *AuthorizeRequest) error {
// https://tools.ietf.org/html/rfc6749#section-3.1.1
// Extension response types MAY contain a space-delimited (%x20) list of
// values, where the order of values does not matter (e.g., response
// type "a b" is the same as "b a"). The meaning of such composite
// response types is defined by their respective specifications.
responseTypes := RemoveEmpty(stringsx.Splitx(r.Form.Get("response_type"), " "))
if len(responseTypes) == 0 {
return errors.WithStack(ErrUnsupportedResponseType.WithHint(`The request is missing the "response_type"" parameter.`))
}
var found bool
for _, t := range request.GetClient().GetResponseTypes() {
if Arguments(responseTypes).Matches(RemoveEmpty(stringsx.Splitx(t, " "))...) {
found = true
break
}
}
if !found {
return errors.WithStack(ErrUnsupportedResponseType.WithHintf("The client is not allowed to request response_type \"%s\".", r.Form.Get("response_type")))
}
request.ResponseTypes = responseTypes
return nil
}
func (f *Fosite) NewAuthorizeRequest(ctx context.Context, r *http.Request) (AuthorizeRequester, error) {
request := &AuthorizeRequest{
ResponseTypes: Arguments{},
HandledResponseTypes: Arguments{},
Request: *NewRequest(),
}
if err := r.ParseMultipartForm(1 << 20); err != nil && err != http.ErrNotMultipart {
return request, errors.WithStack(ErrInvalidRequest.WithHint("Unable to parse HTTP body, make sure to send a properly formatted form request body.").WithDebug(err.Error()))
}
request.Form = r.Form
// Save state to the request to be returned in error conditions (https://github.com/ory/hydra/issues/1642)
state := request.Form.Get("state")
request.State = state
client, err := f.Store.GetClient(ctx, request.GetRequestForm().Get("client_id"))
if err != nil {
return request, errors.WithStack(ErrInvalidClient.WithHint("The requested OAuth 2.0 Client does not exist.").WithDebug(err.Error()))
}
request.Client = client
if err := f.authorizeRequestParametersFromOpenIDConnectRequest(request); err != nil {
return request, err
}
if err := f.validateAuthorizeRedirectURI(r, request); err != nil {
return request, err
}
if err := f.validateAuthorizeScope(r, request); err != nil {
return request, err
}
if err := f.validateAuthorizeAudience(r, request); err != nil {
return request, err
}
if len(request.Form.Get("registration")) > 0 {
return request, errors.WithStack(ErrRegistrationNotSupported)
}
if err := f.validateResponseTypes(r, request); err != nil {
return request, err
}
// rfc6819 4.4.1.8. Threat: CSRF Attack against redirect-uri
// The "state" parameter should be used to link the authorization
// request with the redirect URI used to deliver the access token (Section 5.3.5).
//
// https://tools.ietf.org/html/rfc6819#section-4.4.1.8
// The "state" parameter should not be guessable
if len(state) < MinParameterEntropy {
// We're assuming that using less then 8 characters for the state can not be considered "unguessable"
return request, errors.WithStack(ErrInvalidState.WithHintf(`Request parameter "state" must be at least be %d characters long to ensure sufficient entropy.`, MinParameterEntropy))
}
return request, nil
}

77
vendor/github.com/ory/fosite/authorize_response.go generated vendored Normal file
View File

@ -0,0 +1,77 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package fosite
import (
"net/http"
"net/url"
)
// AuthorizeResponse is an implementation of AuthorizeResponder
type AuthorizeResponse struct {
Header http.Header
Query url.Values
Fragment url.Values
code string
}
func NewAuthorizeResponse() *AuthorizeResponse {
return &AuthorizeResponse{
Header: http.Header{},
Query: url.Values{},
Fragment: url.Values{},
}
}
func (a *AuthorizeResponse) GetCode() string {
return a.code
}
func (a *AuthorizeResponse) GetHeader() http.Header {
return a.Header
}
func (a *AuthorizeResponse) AddHeader(key, value string) {
a.Header.Add(key, value)
}
func (a *AuthorizeResponse) GetQuery() url.Values {
return a.Query
}
func (a *AuthorizeResponse) GetFragment() url.Values {
return a.Fragment
}
func (a *AuthorizeResponse) AddQuery(key, value string) {
if key == "code" {
a.code = value
}
a.Query.Add(key, value)
}
func (a *AuthorizeResponse) AddFragment(key, value string) {
if key == "code" {
a.code = value
}
a.Fragment.Add(key, value)
}

View File

@ -0,0 +1,51 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package fosite
import (
"context"
"net/http"
"net/url"
"github.com/pkg/errors"
)
func (f *Fosite) NewAuthorizeResponse(ctx context.Context, ar AuthorizeRequester, session Session) (AuthorizeResponder, error) {
var resp = &AuthorizeResponse{
Header: http.Header{},
Query: url.Values{},
Fragment: url.Values{},
}
ar.SetSession(session)
for _, h := range f.AuthorizeEndpointHandlers {
if err := h.HandleAuthorizeEndpointRequest(ctx, ar, resp); err != nil {
return nil, err
}
}
if !ar.DidHandleAllResponseTypes() {
return nil, errors.WithStack(ErrUnsupportedResponseType)
}
return resp, nil
}

72
vendor/github.com/ory/fosite/authorize_write.go generated vendored Normal file
View File

@ -0,0 +1,72 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package fosite
import (
"net/http"
"regexp"
)
var (
// scopeMatch = regexp.MustCompile("scope=[^\\&]+.*$")
plusMatch = regexp.MustCompile("\\+")
)
func (f *Fosite) WriteAuthorizeResponse(rw http.ResponseWriter, ar AuthorizeRequester, resp AuthorizeResponder) {
redir := ar.GetRedirectURI()
// Explicit grants
q := redir.Query()
rq := resp.GetQuery()
for k := range rq {
q.Set(k, rq.Get(k))
}
redir.RawQuery = q.Encode()
// Set custom headers, e.g. "X-MySuperCoolCustomHeader" or "X-DONT-CACHE-ME"...
wh := rw.Header()
rh := resp.GetHeader()
for k := range rh {
wh.Set(k, rh.Get(k))
}
// Implicit grants
// The endpoint URI MUST NOT include a fragment component.
redir.Fragment = ""
u := redir.String()
fr := resp.GetFragment()
if len(fr) > 0 {
u = u + "#" + fr.Encode()
}
u = plusMatch.ReplaceAllString(u, "%20")
// https://tools.ietf.org/html/rfc6749#section-4.1.1
// When a decision is established, the authorization server directs the
// user-agent to the provided client redirection URI using an HTTP
// redirection response, or by other means available to it via the
// user-agent.
wh.Set("Location", u)
rw.WriteHeader(http.StatusFound)
}

179
vendor/github.com/ory/fosite/client.go generated vendored Normal file
View File

@ -0,0 +1,179 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package fosite
import jose "gopkg.in/square/go-jose.v2"
// Client represents a client or an app.
type Client interface {
// GetID returns the client ID.
GetID() string
// GetHashedSecret returns the hashed secret as it is stored in the store.
GetHashedSecret() []byte
// GetRedirectURIs returns the client's allowed redirect URIs.
GetRedirectURIs() []string
// GetGrantTypes returns the client's allowed grant types.
GetGrantTypes() Arguments
// GetResponseTypes returns the client's allowed response types.
// All allowed combinations of response types have to be listed, each combination having
// response types of the combination separated by a space.
GetResponseTypes() Arguments
// GetScopes returns the scopes this client is allowed to request.
GetScopes() Arguments
// IsPublic returns true, if this client is marked as public.
IsPublic() bool
// GetAudience returns the allowed audience(s) for this client.
GetAudience() Arguments
}
// OpenIDConnectClient represents a client capable of performing OpenID Connect requests.
type OpenIDConnectClient interface {
// GetRequestURIs is an array of request_uri values that are pre-registered by the RP for use at the OP. Servers MAY
// cache the contents of the files referenced by these URIs and not retrieve them at the time they are used in a request.
// OPs can require that request_uri values used be pre-registered with the require_request_uri_registration
// discovery parameter.
GetRequestURIs() []string
// GetJSONWebKeys returns the JSON Web Key Set containing the public keys used by the client to authenticate.
GetJSONWebKeys() *jose.JSONWebKeySet
// GetJSONWebKeys returns the URL for lookup of JSON Web Key Set containing the
// public keys used by the client to authenticate.
GetJSONWebKeysURI() string
// JWS [JWS] alg algorithm [JWA] that MUST be used for signing Request Objects sent to the OP.
// All Request Objects from this Client MUST be rejected, if not signed with this algorithm.
GetRequestObjectSigningAlgorithm() string
// Requested Client Authentication method for the Token Endpoint. The options are client_secret_post,
// client_secret_basic, client_secret_jwt, private_key_jwt, and none.
GetTokenEndpointAuthMethod() string
// JWS [JWS] alg algorithm [JWA] that MUST be used for signing the JWT [JWT] used to authenticate the
// Client at the Token Endpoint for the private_key_jwt and client_secret_jwt authentication methods.
GetTokenEndpointAuthSigningAlgorithm() string
}
// DefaultClient is a simple default implementation of the Client interface.
type DefaultClient struct {
ID string `json:"id"`
Secret []byte `json:"client_secret,omitempty"`
RedirectURIs []string `json:"redirect_uris"`
GrantTypes []string `json:"grant_types"`
ResponseTypes []string `json:"response_types"`
Scopes []string `json:"scopes"`
Audience []string `json:"audience"`
Public bool `json:"public"`
}
type DefaultOpenIDConnectClient struct {
*DefaultClient
JSONWebKeysURI string `json:"jwks_uri"`
JSONWebKeys *jose.JSONWebKeySet `json:"jwks"`
TokenEndpointAuthMethod string `json:"token_endpoint_auth_method"`
RequestURIs []string `json:"request_uris"`
RequestObjectSigningAlgorithm string `json:"request_object_signing_alg"`
TokenEndpointAuthSigningAlgorithm string `json:"token_endpoint_auth_signing_alg"`
}
func (c *DefaultClient) GetID() string {
return c.ID
}
func (c *DefaultClient) IsPublic() bool {
return c.Public
}
func (c *DefaultClient) GetAudience() Arguments {
return c.Audience
}
func (c *DefaultClient) GetRedirectURIs() []string {
return c.RedirectURIs
}
func (c *DefaultClient) GetHashedSecret() []byte {
return c.Secret
}
func (c *DefaultClient) GetScopes() Arguments {
return c.Scopes
}
func (c *DefaultClient) GetGrantTypes() Arguments {
// https://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata
//
// JSON array containing a list of the OAuth 2.0 Grant Types that the Client is declaring
// that it will restrict itself to using.
// If omitted, the default is that the Client will use only the authorization_code Grant Type.
if len(c.GrantTypes) == 0 {
return Arguments{"authorization_code"}
}
return Arguments(c.GrantTypes)
}
func (c *DefaultClient) GetResponseTypes() Arguments {
// https://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata
//
// JSON array containing a list of the OAuth 2.0 response_type values that the Client is declaring
// that it will restrict itself to using. If omitted, the default is that the Client will use
// only the code Response Type.
if len(c.ResponseTypes) == 0 {
return Arguments{"code"}
}
return Arguments(c.ResponseTypes)
}
func (c *DefaultOpenIDConnectClient) GetJSONWebKeysURI() string {
return c.JSONWebKeysURI
}
func (c *DefaultOpenIDConnectClient) GetJSONWebKeys() *jose.JSONWebKeySet {
return c.JSONWebKeys
}
func (c *DefaultOpenIDConnectClient) GetTokenEndpointAuthSigningAlgorithm() string {
if c.TokenEndpointAuthSigningAlgorithm == "" {
return "RS256"
} else {
return c.TokenEndpointAuthSigningAlgorithm
}
}
func (c *DefaultOpenIDConnectClient) GetRequestObjectSigningAlgorithm() string {
return c.RequestObjectSigningAlgorithm
}
func (c *DefaultOpenIDConnectClient) GetTokenEndpointAuthMethod() string {
return c.TokenEndpointAuthMethod
}
func (c *DefaultOpenIDConnectClient) GetRequestURIs() []string {
return c.RequestURIs
}

294
vendor/github.com/ory/fosite/client_authentication.go generated vendored Normal file
View File

@ -0,0 +1,294 @@
/*
* Copyright © 2017-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @Copyright 2017-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package fosite
import (
"context"
"crypto/ecdsa"
"crypto/rsa"
"encoding/json"
"fmt"
"net/http"
"net/url"
"time"
jwt "github.com/dgrijalva/jwt-go"
"github.com/pkg/errors"
jose "gopkg.in/square/go-jose.v2"
)
const clientAssertionJWTBearerType = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
func (f *Fosite) findClientPublicJWK(oidcClient OpenIDConnectClient, t *jwt.Token, expectsRSAKey bool) (interface{}, error) {
if set := oidcClient.GetJSONWebKeys(); set != nil {
return findPublicKey(t, set, expectsRSAKey)
}
if location := oidcClient.GetJSONWebKeysURI(); len(location) > 0 {
keys, err := f.JWKSFetcherStrategy.Resolve(location, false)
if err != nil {
return nil, err
}
if key, err := findPublicKey(t, keys, expectsRSAKey); err == nil {
return key, nil
}
keys, err = f.JWKSFetcherStrategy.Resolve(location, true)
if err != nil {
return nil, err
}
return findPublicKey(t, keys, expectsRSAKey)
}
return nil, errors.WithStack(ErrInvalidClient.WithHint("The OAuth 2.0 Client has no JSON Web Keys set registered, but they are needed to complete the request."))
}
func (f *Fosite) AuthenticateClient(ctx context.Context, r *http.Request, form url.Values) (Client, error) {
if assertionType := form.Get("client_assertion_type"); assertionType == clientAssertionJWTBearerType {
assertion := form.Get("client_assertion")
if len(assertion) == 0 {
return nil, errors.WithStack(ErrInvalidRequest.WithHintf("The client_assertion request parameter must be set when using client_assertion_type of \"%s\".", clientAssertionJWTBearerType))
}
var clientID string
var client Client
token, err := jwt.ParseWithClaims(assertion, new(jwt.MapClaims), func(t *jwt.Token) (interface{}, error) {
var err error
clientID, _, err = clientCredentialsFromRequestBody(form, false)
if err != nil {
return nil, err
}
if clientID == "" {
if claims, ok := t.Claims.(*jwt.MapClaims); !ok {
return nil, errors.WithStack(ErrRequestUnauthorized.WithHint("Unable to type assert claims from client_assertion.").WithDebugf(`Expected claims to be of type "*jwt.MapClaims" but got "%T".`, t.Claims))
} else if sub, ok := (*claims)["sub"].(string); !ok {
return nil, errors.WithStack(ErrInvalidClient.WithHint(`The claim "sub" from the client_assertion JSON Web Token is undefined.`))
} else {
clientID = sub
}
}
client, err = f.Store.GetClient(ctx, clientID)
if err != nil {
return nil, errors.WithStack(ErrInvalidClient.WithDebug(err.Error()))
}
oidcClient, ok := client.(OpenIDConnectClient)
if !ok {
return nil, errors.WithStack(ErrInvalidRequest.WithHint("The server configuration does not support OpenID Connect specific authentication methods."))
}
switch oidcClient.GetTokenEndpointAuthMethod() {
case "private_key_jwt":
break
case "none":
return nil, errors.WithStack(ErrInvalidClient.WithHint("This requested OAuth 2.0 client does not support client authentication, however \"client_assertion\" was provided in the request."))
case "client_secret_post":
fallthrough
case "client_secret_basic":
return nil, errors.WithStack(ErrInvalidClient.WithHintf("This requested OAuth 2.0 client only supports client authentication method \"%s\", however \"client_assertion\" was provided in the request.", oidcClient.GetTokenEndpointAuthMethod()))
case "client_secret_jwt":
fallthrough
default:
return nil, errors.WithStack(ErrInvalidClient.WithHintf("This requested OAuth 2.0 client only supports client authentication method \"%s\", however that method is not supported by this server.", oidcClient.GetTokenEndpointAuthMethod()))
}
if oidcClient.GetTokenEndpointAuthSigningAlgorithm() != fmt.Sprintf("%s", t.Header["alg"]) {
return nil, errors.WithStack(ErrInvalidClient.WithHintf(`The "client_assertion" uses signing algorithm "%s", but the requested OAuth 2.0 Client enforces signing algorithm "%s".`, t.Header["alg"], oidcClient.GetTokenEndpointAuthSigningAlgorithm()))
}
if _, ok := t.Method.(*jwt.SigningMethodRSA); ok {
return f.findClientPublicJWK(oidcClient, t, true)
} else if _, ok := t.Method.(*jwt.SigningMethodECDSA); ok {
return f.findClientPublicJWK(oidcClient, t, false)
} else if _, ok := t.Method.(*jwt.SigningMethodRSAPSS); ok {
return f.findClientPublicJWK(oidcClient, t, true)
} else if _, ok := t.Method.(*jwt.SigningMethodHMAC); ok {
return nil, errors.WithStack(ErrInvalidClient.WithHint("This authorization server does not support client authentication method \"client_secret_jwt\"."))
}
return nil, errors.WithStack(ErrInvalidClient.WithHintf(`The "client_assertion" request parameter uses unsupported signing algorithm "%s".`, t.Header["alg"]))
})
if err != nil {
// Do not re-process already enhanced errors
if e, ok := errors.Cause(err).(*jwt.ValidationError); ok {
if e.Inner != nil {
return nil, e.Inner
}
return nil, errors.WithStack(ErrInvalidClient.WithHint("Unable to verify the integrity of the \"client_assertion\" value.").WithDebug(err.Error()))
}
return nil, err
} else if err := token.Claims.Valid(); err != nil {
return nil, errors.WithStack(ErrInvalidClient.WithHint("Unable to verify the request object because its claims could not be validated, check if the expiry time is set correctly.").WithDebug(err.Error()))
}
claims, ok := token.Claims.(*jwt.MapClaims)
if !ok {
return nil, errors.WithStack(ErrInvalidClient.WithHint("Unable to type assert claims from request parameter \"client_assertion\".").WithDebugf(`Got claims of type %T but expected type "*jwt.MapClaims".`, token.Claims))
}
var jti string
if !claims.VerifyIssuer(clientID, true) {
return nil, errors.WithStack(ErrInvalidClient.WithHint("Claim \"iss\" from \"client_assertion\" must match the \"client_id\" of the OAuth 2.0 Client."))
} else if f.TokenURL == "" {
return nil, errors.WithStack(ErrMisconfiguration.WithHint("The authorization server's token endpoint URL has not been set."))
} else if sub, ok := (*claims)["sub"].(string); !ok || sub != clientID {
return nil, errors.WithStack(ErrInvalidClient.WithHint("Claim \"sub\" from \"client_assertion\" must match the \"client_id\" of the OAuth 2.0 Client."))
} else if jti, ok = (*claims)["jti"].(string); !ok || len(jti) == 0 {
return nil, errors.WithStack(ErrInvalidClient.WithHint("Claim \"jti\" from \"client_assertion\" must be set but is not."))
} else if f.Store.ClientAssertionJWTValid(context.Background(), jti) != nil {
return nil, errors.WithStack(ErrJTIKnown.WithHint("Claim \"jti\" from \"client_assertion\" MUST only be used once."))
}
// type conversion according to jwt.MapClaims.VerifyExpiresAt
var expiry int64
err = nil
switch exp := (*claims)["exp"].(type) {
case float64:
expiry = int64(exp)
case json.Number:
expiry, err = exp.Int64()
default:
err = ErrInvalidClient.WithHint("Unable to type assert the expiry time from claims. This should not happen as we validate the expiry time already earlier with token.Claims.Valid()")
}
if err != nil {
return nil, errors.WithStack(err)
}
if err := f.Store.SetClientAssertionJWT(context.Background(), jti, time.Unix(expiry, 0)); err != nil {
return nil, err
}
if auds, ok := (*claims)["aud"].([]interface{}); !ok {
if !claims.VerifyAudience(f.TokenURL, true) {
return nil, errors.WithStack(ErrInvalidClient.WithHintf("Claim \"audience\" from \"client_assertion\" must match the authorization server's token endpoint \"%s\".", f.TokenURL))
}
} else {
var found bool
for _, aud := range auds {
if a, ok := aud.(string); ok && a == f.TokenURL {
found = true
break
}
}
if !found {
return nil, errors.WithStack(ErrInvalidClient.WithHintf("Claim \"audience\" from \"client_assertion\" must match the authorization server's token endpoint \"%s\".", f.TokenURL))
}
}
return client, nil
} else if len(assertionType) > 0 {
return nil, errors.WithStack(ErrInvalidRequest.WithHintf("Unknown client_assertion_type \"%s\".", assertionType))
}
clientID, clientSecret, err := clientCredentialsFromRequest(r, form)
if err != nil {
return nil, err
}
client, err := f.Store.GetClient(ctx, clientID)
if err != nil {
return nil, errors.WithStack(ErrInvalidClient.WithDebug(err.Error()))
}
if oidcClient, ok := client.(OpenIDConnectClient); !ok {
// If this isn't an OpenID Connect client then we actually don't care about any of this, just continue!
} else if ok && form.Get("client_id") != "" && form.Get("client_secret") != "" && oidcClient.GetTokenEndpointAuthMethod() != "client_secret_post" {
return nil, errors.WithStack(ErrInvalidClient.WithHintf("The OAuth 2.0 Client supports client authentication method \"%s\", but method \"client_secret_post\" was requested. You must configure the OAuth 2.0 client's \"token_endpoint_auth_method\" value to accept \"client_secret_post\".", oidcClient.GetTokenEndpointAuthMethod()))
} else if _, _, basicOk := r.BasicAuth(); basicOk && ok && oidcClient.GetTokenEndpointAuthMethod() != "client_secret_basic" {
return nil, errors.WithStack(ErrInvalidClient.WithHintf("The OAuth 2.0 Client supports client authentication method \"%s\", but method \"client_secret_basic\" was requested. You must configure the OAuth 2.0 client's \"token_endpoint_auth_method\" value to accept \"client_secret_basic\".", oidcClient.GetTokenEndpointAuthMethod()))
} else if ok && oidcClient.GetTokenEndpointAuthMethod() != "none" && client.IsPublic() {
return nil, errors.WithStack(ErrInvalidClient.WithHintf("The OAuth 2.0 Client supports client authentication method \"%s\", but method \"none\" was requested. You must configure the OAuth 2.0 client's \"token_endpoint_auth_method\" value to accept \"none\".", oidcClient.GetTokenEndpointAuthMethod()))
}
if client.IsPublic() {
return client, nil
}
// Enforce client authentication
if err := f.Hasher.Compare(ctx, client.GetHashedSecret(), []byte(clientSecret)); err != nil {
return nil, errors.WithStack(ErrInvalidClient.WithDebug(err.Error()))
}
return client, nil
}
func findPublicKey(t *jwt.Token, set *jose.JSONWebKeySet, expectsRSAKey bool) (interface{}, error) {
kid, ok := t.Header["kid"].(string)
if !ok {
return nil, errors.WithStack(ErrInvalidRequest.WithHint("The JSON Web Token must contain a kid header value but did not."))
}
keys := set.Key(kid)
if len(keys) == 0 {
return nil, errors.WithStack(ErrInvalidRequest.WithHintf("The JSON Web Token uses signing key with kid \"%s\", which could not be found.", kid))
}
for _, key := range keys {
if key.Use != "sig" {
continue
}
if expectsRSAKey {
if k, ok := key.Key.(*rsa.PublicKey); ok {
return k, nil
}
} else {
if k, ok := key.Key.(*ecdsa.PublicKey); ok {
return k, nil
}
}
}
if expectsRSAKey {
return nil, errors.WithStack(ErrInvalidRequest.WithHintf("Unable to find RSA public key with use=\"sig\" for kid \"%s\" in JSON Web Key Set.", kid))
} else {
return nil, errors.WithStack(ErrInvalidRequest.WithHintf("Unable to find ECDSA public key with use=\"sig\" for kid \"%s\" in JSON Web Key Set.", kid))
}
}
func clientCredentialsFromRequest(r *http.Request, form url.Values) (clientID, clientSecret string, err error) {
if id, secret, ok := r.BasicAuth(); !ok {
return clientCredentialsFromRequestBody(form, true)
} else if clientID, err = url.QueryUnescape(id); err != nil {
return "", "", errors.WithStack(ErrInvalidRequest.WithHint(`The client id in the HTTP authorization header could not be decoded from "application/x-www-form-urlencoded".`).WithDebug(err.Error()))
} else if clientSecret, err = url.QueryUnescape(secret); err != nil {
return "", "", errors.WithStack(ErrInvalidRequest.WithHint(`The client secret in the HTTP authorization header could not be decoded from "application/x-www-form-urlencoded".`).WithDebug(err.Error()))
}
return clientID, clientSecret, nil
}
func clientCredentialsFromRequestBody(form url.Values, forceID bool) (clientID, clientSecret string, err error) {
clientID = form.Get("client_id")
clientSecret = form.Get("client_secret")
if clientID == "" && forceID {
return "", "", errors.WithStack(ErrInvalidRequest.WithHint("Client credentials missing or malformed in both HTTP Authorization header and HTTP POST body."))
}
return clientID, clientSecret, nil
}

View File

@ -0,0 +1,81 @@
/*
* Copyright © 2017-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @Copyright 2017-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package fosite
import (
"encoding/json"
"net/http"
"sync"
"github.com/pkg/errors"
jose "gopkg.in/square/go-jose.v2"
)
// JWKSFetcherStrategy is a strategy which pulls (optionally caches) JSON Web Key Sets from a location,
// typically a client's jwks_uri.
type JWKSFetcherStrategy interface {
// Resolve returns the JSON Web Key Set, or an error if something went wrong. The forceRefresh, if true, forces
// the strategy to fetch the keys from the remote. If forceRefresh is false, the strategy may use a caching strategy
// to fetch the key.
Resolve(location string, forceRefresh bool) (*jose.JSONWebKeySet, error)
}
type DefaultJWKSFetcherStrategy struct {
client *http.Client
keys map[string]jose.JSONWebKeySet
sync.Mutex
}
func NewDefaultJWKSFetcherStrategy() JWKSFetcherStrategy {
return &DefaultJWKSFetcherStrategy{
keys: make(map[string]jose.JSONWebKeySet),
client: http.DefaultClient,
}
}
func (s *DefaultJWKSFetcherStrategy) Resolve(location string, forceRefresh bool) (*jose.JSONWebKeySet, error) {
s.Lock()
defer s.Unlock()
keys, ok := s.keys[location]
if !ok || forceRefresh {
response, err := s.client.Get(location)
if err != nil {
return nil, errors.WithStack(ErrServerError.WithHintf(`Unable to fetch JSON Web Keys from location "%s" because %s"`, location, err))
}
defer response.Body.Close()
if response.StatusCode < 200 || response.StatusCode >= 400 {
return nil, errors.WithStack(ErrServerError.WithHintf(`Expected successful status code from location "%s", but received code "%d".`, location, response.StatusCode))
}
var set jose.JSONWebKeySet
if err := json.NewDecoder(response.Body).Decode(&set); err != nil {
return nil, errors.WithStack(ErrServerError.WithHintf("Unable to decode JSON Web Keys from location \"%s\" because \"%s\".", location, err))
}
s.keys[location] = set
return &set, nil
}
return &keys, nil
}

42
vendor/github.com/ory/fosite/client_manager.go generated vendored Normal file
View File

@ -0,0 +1,42 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package fosite
import (
"context"
"time"
)
// ClientManager defines the (persistent) manager interface for clients.
type ClientManager interface {
// GetClient loads the client by its ID or returns an error
// if the client does not exist or another error occurred.
GetClient(ctx context.Context, id string) (Client, error)
// ClientAssertionJWTValid returns an error if the JTI is
// known or the DB check failed and nil if the JTI is not known.
ClientAssertionJWTValid(ctx context.Context, jti string) error
// SetClientAssertionJWT marks a JTI as known for the given
// expiry time. Before inserting the new JTI, it will clean
// up any existing JTIs that have expired as those tokens can
// not be replayed due to the expiry.
SetClientAssertionJWT(ctx context.Context, jti string, exp time.Time) error
}

122
vendor/github.com/ory/fosite/compose/compose.go generated vendored Normal file
View File

@ -0,0 +1,122 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package compose
import (
"crypto/rsa"
"github.com/ory/fosite"
"github.com/ory/fosite/token/jwt"
)
type Factory func(config *Config, storage interface{}, strategy interface{}) interface{}
// Compose takes a config, a storage, a strategy and handlers to instantiate an OAuth2Provider:
//
// import "github.com/ory/fosite/compose"
//
// // var storage = new(MyFositeStorage)
// var config = Config {
// AccessTokenLifespan: time.Minute * 30,
// // check Config for further configuration options
// }
//
// var strategy = NewOAuth2HMACStrategy(config)
//
// var oauth2Provider = Compose(
// config,
// storage,
// strategy,
// NewOAuth2AuthorizeExplicitHandler,
// OAuth2ClientCredentialsGrantFactory,
// // for a complete list refer to the docs of this package
// )
//
// Compose makes use of interface{} types in order to be able to handle a all types of stores, strategies and handlers.
func Compose(config *Config, storage interface{}, strategy interface{}, hasher fosite.Hasher, factories ...Factory) fosite.OAuth2Provider {
if hasher == nil {
hasher = &fosite.BCrypt{WorkFactor: config.GetHashCost()}
}
f := &fosite.Fosite{
Store: storage.(fosite.Storage),
AuthorizeEndpointHandlers: fosite.AuthorizeEndpointHandlers{},
TokenEndpointHandlers: fosite.TokenEndpointHandlers{},
TokenIntrospectionHandlers: fosite.TokenIntrospectionHandlers{},
RevocationHandlers: fosite.RevocationHandlers{},
Hasher: hasher,
ScopeStrategy: config.GetScopeStrategy(),
AudienceMatchingStrategy: config.GetAudienceStrategy(),
SendDebugMessagesToClients: config.SendDebugMessagesToClients,
TokenURL: config.TokenURL,
JWKSFetcherStrategy: config.GetJWKSFetcherStrategy(),
}
for _, factory := range factories {
res := factory(config, storage, strategy)
if ah, ok := res.(fosite.AuthorizeEndpointHandler); ok {
f.AuthorizeEndpointHandlers.Append(ah)
}
if th, ok := res.(fosite.TokenEndpointHandler); ok {
f.TokenEndpointHandlers.Append(th)
}
if tv, ok := res.(fosite.TokenIntrospector); ok {
f.TokenIntrospectionHandlers.Append(tv)
}
if rh, ok := res.(fosite.RevocationHandler); ok {
f.RevocationHandlers.Append(rh)
}
}
return f
}
// ComposeAllEnabled returns a fosite instance with all OAuth2 and OpenID Connect handlers enabled.
func ComposeAllEnabled(config *Config, storage interface{}, secret []byte, key *rsa.PrivateKey) fosite.OAuth2Provider {
return Compose(
config,
storage,
&CommonStrategy{
CoreStrategy: NewOAuth2HMACStrategy(config, secret, nil),
OpenIDConnectTokenStrategy: NewOpenIDConnectStrategy(config, key),
JWTStrategy: &jwt.RS256JWTStrategy{
PrivateKey: key,
},
},
nil,
OAuth2AuthorizeExplicitFactory,
OAuth2AuthorizeImplicitFactory,
OAuth2ClientCredentialsGrantFactory,
OAuth2RefreshTokenGrantFactory,
OAuth2ResourceOwnerPasswordCredentialsFactory,
OpenIDConnectExplicitFactory,
OpenIDConnectImplicitFactory,
OpenIDConnectHybridFactory,
OpenIDConnectRefreshFactory,
OAuth2TokenIntrospectionFactory,
OAuth2PKCEFactory,
)
}

138
vendor/github.com/ory/fosite/compose/compose_oauth2.go generated vendored Normal file
View File

@ -0,0 +1,138 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package compose
import (
"github.com/ory/fosite/handler/oauth2"
)
// OAuth2AuthorizeExplicitFactory creates an OAuth2 authorize code grant ("authorize explicit flow") handler and registers
// an access token, refresh token and authorize code validator.
func OAuth2AuthorizeExplicitFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
return &oauth2.AuthorizeExplicitGrantHandler{
AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy),
AuthorizeCodeStrategy: strategy.(oauth2.AuthorizeCodeStrategy),
CoreStorage: storage.(oauth2.CoreStorage),
AuthCodeLifespan: config.GetAuthorizeCodeLifespan(),
RefreshTokenLifespan: config.GetRefreshTokenLifespan(),
AccessTokenLifespan: config.GetAccessTokenLifespan(),
ScopeStrategy: config.GetScopeStrategy(),
AudienceMatchingStrategy: config.GetAudienceStrategy(),
TokenRevocationStorage: storage.(oauth2.TokenRevocationStorage),
IsRedirectURISecure: config.GetRedirectSecureChecker(),
RefreshTokenScopes: config.GetRefreshTokenScopes(),
}
}
// OAuth2ClientCredentialsGrantFactory creates an OAuth2 client credentials grant handler and registers
// an access token, refresh token and authorize code validator.
func OAuth2ClientCredentialsGrantFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
return &oauth2.ClientCredentialsGrantHandler{
HandleHelper: &oauth2.HandleHelper{
AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
AccessTokenStorage: storage.(oauth2.AccessTokenStorage),
AccessTokenLifespan: config.GetAccessTokenLifespan(),
},
ScopeStrategy: config.GetScopeStrategy(),
AudienceMatchingStrategy: config.GetAudienceStrategy(),
}
}
// OAuth2RefreshTokenGrantFactory creates an OAuth2 refresh grant handler and registers
// an access token, refresh token and authorize code validator.
func OAuth2RefreshTokenGrantFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
return &oauth2.RefreshTokenGrantHandler{
AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy),
TokenRevocationStorage: storage.(oauth2.TokenRevocationStorage),
AccessTokenLifespan: config.GetAccessTokenLifespan(),
RefreshTokenLifespan: config.GetRefreshTokenLifespan(),
ScopeStrategy: config.GetScopeStrategy(),
AudienceMatchingStrategy: config.GetAudienceStrategy(),
RefreshTokenScopes: config.GetRefreshTokenScopes(),
}
}
// OAuth2AuthorizeImplicitFactory creates an OAuth2 implicit grant ("authorize implicit flow") handler and registers
// an access token, refresh token and authorize code validator.
func OAuth2AuthorizeImplicitFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
return &oauth2.AuthorizeImplicitGrantTypeHandler{
AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
AccessTokenStorage: storage.(oauth2.AccessTokenStorage),
AccessTokenLifespan: config.GetAccessTokenLifespan(),
ScopeStrategy: config.GetScopeStrategy(),
AudienceMatchingStrategy: config.GetAudienceStrategy(),
}
}
// OAuth2ResourceOwnerPasswordCredentialsFactory creates an OAuth2 resource owner password credentials grant handler and registers
// an access token, refresh token and authorize code validator.
func OAuth2ResourceOwnerPasswordCredentialsFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
return &oauth2.ResourceOwnerPasswordCredentialsGrantHandler{
ResourceOwnerPasswordCredentialsGrantStorage: storage.(oauth2.ResourceOwnerPasswordCredentialsGrantStorage),
HandleHelper: &oauth2.HandleHelper{
AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
AccessTokenStorage: storage.(oauth2.AccessTokenStorage),
AccessTokenLifespan: config.GetAccessTokenLifespan(),
RefreshTokenLifespan: config.GetRefreshTokenLifespan(),
},
RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy),
ScopeStrategy: config.GetScopeStrategy(),
AudienceMatchingStrategy: config.GetAudienceStrategy(),
RefreshTokenScopes: config.GetRefreshTokenScopes(),
}
}
// OAuth2TokenRevocationFactory creates an OAuth2 token revocation handler.
func OAuth2TokenRevocationFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
return &oauth2.TokenRevocationHandler{
TokenRevocationStorage: storage.(oauth2.TokenRevocationStorage),
AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy),
}
}
// OAuth2TokenIntrospectionFactory creates an OAuth2 token introspection handler and registers
// an access token and refresh token validator.
func OAuth2TokenIntrospectionFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
return &oauth2.CoreValidator{
CoreStrategy: strategy.(oauth2.CoreStrategy),
CoreStorage: storage.(oauth2.CoreStorage),
ScopeStrategy: config.GetScopeStrategy(),
DisableRefreshTokenValidation: config.DisableRefreshTokenValidation,
}
}
// OAuth2StatelessJWTIntrospectionFactory creates an OAuth2 token introspection handler and
// registers an access token validator. This can only be used to validate JWTs and does so
// statelessly, meaning it uses only the data available in the JWT itself, and does not access the
// storage implementation at all.
//
// Due to the stateless nature of this factory, THE BUILT-IN REVOCATION MECHANISMS WILL NOT WORK.
// If you need revocation, you can validate JWTs statefully, using the other factories.
func OAuth2StatelessJWTIntrospectionFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
return &oauth2.StatelessJWTValidator{
JWTAccessTokenStrategy: strategy.(oauth2.JWTAccessTokenStrategy),
ScopeStrategy: config.GetScopeStrategy(),
}
}

99
vendor/github.com/ory/fosite/compose/compose_openid.go generated vendored Normal file
View File

@ -0,0 +1,99 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package compose
import (
"github.com/ory/fosite/handler/oauth2"
"github.com/ory/fosite/handler/openid"
"github.com/ory/fosite/token/jwt"
)
// OpenIDConnectExplicitFactory creates an OpenID Connect explicit ("authorize code flow") grant handler.
//
// **Important note:** You must add this handler *after* you have added an OAuth2 authorize code handler!
func OpenIDConnectExplicitFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
return &openid.OpenIDConnectExplicitHandler{
OpenIDConnectRequestStorage: storage.(openid.OpenIDConnectRequestStorage),
IDTokenHandleHelper: &openid.IDTokenHandleHelper{
IDTokenStrategy: strategy.(openid.OpenIDConnectTokenStrategy),
},
OpenIDConnectRequestValidator: openid.NewOpenIDConnectRequestValidator(config.AllowedPromptValues, strategy.(jwt.JWTStrategy)),
}
}
// OpenIDConnectRefreshFactory creates a handler for refreshing openid connect tokens.
//
// **Important note:** You must add this handler *after* you have added an OAuth2 authorize code handler!
func OpenIDConnectRefreshFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
return &openid.OpenIDConnectRefreshHandler{
IDTokenHandleHelper: &openid.IDTokenHandleHelper{
IDTokenStrategy: strategy.(openid.OpenIDConnectTokenStrategy),
},
}
}
// OpenIDConnectImplicitFactory creates an OpenID Connect implicit ("implicit flow") grant handler.
//
// **Important note:** You must add this handler *after* you have added an OAuth2 authorize code handler!
func OpenIDConnectImplicitFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
return &openid.OpenIDConnectImplicitHandler{
AuthorizeImplicitGrantTypeHandler: &oauth2.AuthorizeImplicitGrantTypeHandler{
AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
AccessTokenStorage: storage.(oauth2.AccessTokenStorage),
AccessTokenLifespan: config.GetAccessTokenLifespan(),
},
ScopeStrategy: config.GetScopeStrategy(),
IDTokenHandleHelper: &openid.IDTokenHandleHelper{
IDTokenStrategy: strategy.(openid.OpenIDConnectTokenStrategy),
},
OpenIDConnectRequestValidator: openid.NewOpenIDConnectRequestValidator(config.AllowedPromptValues, strategy.(jwt.JWTStrategy)),
}
}
// OpenIDConnectHybridFactory creates an OpenID Connect hybrid grant handler.
//
// **Important note:** You must add this handler *after* you have added an OAuth2 authorize code handler!
func OpenIDConnectHybridFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
return &openid.OpenIDConnectHybridHandler{
AuthorizeExplicitGrantHandler: &oauth2.AuthorizeExplicitGrantHandler{
AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
RefreshTokenStrategy: strategy.(oauth2.RefreshTokenStrategy),
AuthorizeCodeStrategy: strategy.(oauth2.AuthorizeCodeStrategy),
CoreStorage: storage.(oauth2.CoreStorage),
AuthCodeLifespan: config.GetAuthorizeCodeLifespan(),
AccessTokenLifespan: config.GetAccessTokenLifespan(),
RefreshTokenLifespan: config.GetRefreshTokenLifespan(),
IsRedirectURISecure: config.GetRedirectSecureChecker(),
},
ScopeStrategy: config.GetScopeStrategy(),
AuthorizeImplicitGrantTypeHandler: &oauth2.AuthorizeImplicitGrantTypeHandler{
AccessTokenStrategy: strategy.(oauth2.AccessTokenStrategy),
AccessTokenStorage: storage.(oauth2.AccessTokenStorage),
AccessTokenLifespan: config.GetAccessTokenLifespan(),
},
IDTokenHandleHelper: &openid.IDTokenHandleHelper{
IDTokenStrategy: strategy.(openid.OpenIDConnectTokenStrategy),
},
OpenIDConnectRequestStorage: storage.(openid.OpenIDConnectRequestStorage),
OpenIDConnectRequestValidator: openid.NewOpenIDConnectRequestValidator(config.AllowedPromptValues, strategy.(jwt.JWTStrategy)),
}
}

38
vendor/github.com/ory/fosite/compose/compose_pkce.go generated vendored Normal file
View File

@ -0,0 +1,38 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package compose
import (
"github.com/ory/fosite/handler/oauth2"
"github.com/ory/fosite/handler/pkce"
)
// OAuth2PKCEFactory creates a PKCE handler.
func OAuth2PKCEFactory(config *Config, storage interface{}, strategy interface{}) interface{} {
return &pkce.Handler{
AuthorizeCodeStrategy: strategy.(oauth2.AuthorizeCodeStrategy),
Storage: storage.(pkce.PKCERequestStorage),
Force: config.EnforcePKCE,
ForceForPublicClients: config.EnforcePKCEForPublicClients,
EnablePlainChallengeMethod: config.EnablePKCEPlainChallengeMethod,
}
}

View File

@ -0,0 +1,79 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package compose
import (
"crypto/rsa"
"github.com/ory/fosite/handler/oauth2"
"github.com/ory/fosite/handler/openid"
"github.com/ory/fosite/token/hmac"
"github.com/ory/fosite/token/jwt"
)
type CommonStrategy struct {
oauth2.CoreStrategy
openid.OpenIDConnectTokenStrategy
jwt.JWTStrategy
}
func NewOAuth2HMACStrategy(config *Config, secret []byte, rotatedSecrets [][]byte) *oauth2.HMACSHAStrategy {
return &oauth2.HMACSHAStrategy{
Enigma: &hmac.HMACStrategy{
GlobalSecret: secret,
RotatedGlobalSecrets: rotatedSecrets,
TokenEntropy: config.GetTokenEntropy(),
},
AccessTokenLifespan: config.GetAccessTokenLifespan(),
AuthorizeCodeLifespan: config.GetAuthorizeCodeLifespan(),
RefreshTokenLifespan: config.GetRefreshTokenLifespan(),
}
}
func NewOAuth2JWTStrategy(key *rsa.PrivateKey, strategy *oauth2.HMACSHAStrategy) *oauth2.DefaultJWTStrategy {
return &oauth2.DefaultJWTStrategy{
JWTStrategy: &jwt.RS256JWTStrategy{
PrivateKey: key,
},
HMACSHAStrategy: strategy,
}
}
func NewOAuth2JWTStrategyWithIssuer(key *rsa.PrivateKey, strategy *oauth2.HMACSHAStrategy, issuer string) *oauth2.DefaultJWTStrategy {
return &oauth2.DefaultJWTStrategy{
JWTStrategy: &jwt.RS256JWTStrategy{
PrivateKey: key,
},
HMACSHAStrategy: strategy,
Issuer: issuer,
}
}
func NewOpenIDConnectStrategy(config *Config, key *rsa.PrivateKey) *openid.DefaultStrategy {
return &openid.DefaultStrategy{
JWTStrategy: &jwt.RS256JWTStrategy{
PrivateKey: key,
},
Expiry: config.GetIDTokenLifespan(),
Issuer: config.IDTokenIssuer,
}
}

184
vendor/github.com/ory/fosite/compose/config.go generated vendored Normal file
View File

@ -0,0 +1,184 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package compose
import (
"net/url"
"time"
"github.com/ory/fosite"
)
type Config struct {
// AccessTokenLifespan sets how long an access token is going to be valid. Defaults to one hour.
AccessTokenLifespan time.Duration
// RefreshTokenLifespan sets how long a refresh token is going to be valid. Defaults to 30 days. Set to -1 for
// refresh tokens that never expire.
RefreshTokenLifespan time.Duration
// AuthorizeCodeLifespan sets how long an authorize code is going to be valid. Defaults to fifteen minutes.
AuthorizeCodeLifespan time.Duration
// IDTokenLifespan sets the default id token lifetime. Defaults to one hour.
IDTokenLifespan time.Duration
// IDTokenIssuer sets the default issuer of the ID Token.
IDTokenIssuer string
// HashCost sets the cost of the password hashing cost. Defaults to 12.
HashCost int
// DisableRefreshTokenValidation sets the introspection endpoint to disable refresh token validation.
DisableRefreshTokenValidation bool
// SendDebugMessagesToClients if set to true, includes error debug messages in response payloads. Be aware that sensitive
// data may be exposed, depending on your implementation of Fosite. Such sensitive data might include database error
// codes or other information. Proceed with caution!
SendDebugMessagesToClients bool
// ScopeStrategy sets the scope strategy that should be supported, for example fosite.WildcardScopeStrategy.
ScopeStrategy fosite.ScopeStrategy
// AudienceMatchingStrategy sets the audience matching strategy that should be supported, defaults to fosite.DefaultsAudienceMatchingStrategy.
AudienceMatchingStrategy fosite.AudienceMatchingStrategy
// EnforcePKCE, if set to true, requires clients to perform authorize code flows with PKCE. Defaults to false.
EnforcePKCE bool
// EnforcePKCEForPublicClients requires only public clients to use PKCE with the authorize code flow. Defaults to false.
EnforcePKCEForPublicClients bool
// EnablePKCEPlainChallengeMethod sets whether or not to allow the plain challenge method (S256 should be used whenever possible, plain is really discouraged). Defaults to false.
EnablePKCEPlainChallengeMethod bool
// AllowedPromptValues sets which OpenID Connect prompt values the server supports. Defaults to []string{"login", "none", "consent", "select_account"}.
AllowedPromptValues []string
// TokenURL is the the URL of the Authorization Server's Token Endpoint. If the authorization server is intended
// to be compatible with the private_key_jwt client authentication method (see http://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth),
// this value MUST be set.
TokenURL string
// JWKSFetcherStrategy is responsible for fetching JSON Web Keys from remote URLs. This is required when the private_key_jwt
// client authentication method is used. Defaults to fosite.DefaultJWKSFetcherStrategy.
JWKSFetcher fosite.JWKSFetcherStrategy
// TokenEntropy indicates the entropy of the random string, used as the "message" part of the HMAC token.
// Defaults to 32.
TokenEntropy int
// RedirectSecureChecker is a function that returns true if the provided URL can be securely used as a redirect URL.
RedirectSecureChecker func(*url.URL) bool
// RefreshTokenScopes defines which OAuth scopes will be given refresh tokens during the authorization code grant exchange. This defaults to "offline" and "offline_access". When set to an empty array, all exchanges will be given refresh tokens.
RefreshTokenScopes []string
}
// GetScopeStrategy returns the scope strategy to be used. Defaults to glob scope strategy.
func (c *Config) GetScopeStrategy() fosite.ScopeStrategy {
if c.ScopeStrategy == nil {
c.ScopeStrategy = fosite.WildcardScopeStrategy
}
return c.ScopeStrategy
}
// GetAudienceStrategy returns the scope strategy to be used. Defaults to glob scope strategy.
func (c *Config) GetAudienceStrategy() fosite.AudienceMatchingStrategy {
if c.AudienceMatchingStrategy == nil {
c.AudienceMatchingStrategy = fosite.DefaultAudienceMatchingStrategy
}
return c.AudienceMatchingStrategy
}
// GetAuthorizeCodeLifespan returns how long an authorize code should be valid. Defaults to one fifteen minutes.
func (c *Config) GetAuthorizeCodeLifespan() time.Duration {
if c.AuthorizeCodeLifespan == 0 {
return time.Minute * 15
}
return c.AuthorizeCodeLifespan
}
// GeIDTokenLifespan returns how long an id token should be valid. Defaults to one hour.
func (c *Config) GetIDTokenLifespan() time.Duration {
if c.IDTokenLifespan == 0 {
return time.Hour
}
return c.IDTokenLifespan
}
// GetAccessTokenLifespan returns how long an access token should be valid. Defaults to one hour.
func (c *Config) GetAccessTokenLifespan() time.Duration {
if c.AccessTokenLifespan == 0 {
return time.Hour
}
return c.AccessTokenLifespan
}
// GetRefreshTokenLifespan sets how long a refresh token is going to be valid. Defaults to 30 days. Set to -1 for
// refresh tokens that never expire.
func (c *Config) GetRefreshTokenLifespan() time.Duration {
if c.RefreshTokenLifespan == 0 {
return time.Hour * 24 * 30
}
return c.RefreshTokenLifespan
}
// GetHashCost returns the bcrypt cost factor. Defaults to 12.
func (c *Config) GetHashCost() int {
if c.HashCost == 0 {
return fosite.DefaultBCryptWorkFactor
}
return c.HashCost
}
// GetJWKSFetcherStrategy returns the JWKSFetcherStrategy.
func (c *Config) GetJWKSFetcherStrategy() fosite.JWKSFetcherStrategy {
if c.JWKSFetcher == nil {
c.JWKSFetcher = fosite.NewDefaultJWKSFetcherStrategy()
}
return c.JWKSFetcher
}
// GetTokenEntropy returns the entropy of the "message" part of a HMAC Token. Defaults to 32.
func (c *Config) GetTokenEntropy() int {
if c.TokenEntropy == 0 {
return 32
}
return c.TokenEntropy
}
// GetTokenEntropy returns the entropy of the "message" part of a HMAC Token. Defaults to 32.
func (c *Config) GetRedirectSecureChecker() func(*url.URL) bool {
if c.RedirectSecureChecker == nil {
return fosite.IsRedirectURISecure
}
return c.RedirectSecureChecker
}
// GetRefreshTokenScopes returns which scopes will provide refresh tokens.
func (c *Config) GetRefreshTokenScopes() []string {
if c.RefreshTokenScopes == nil {
return []string{"offline", "offline_access"}
}
return c.RefreshTokenScopes
}

28
vendor/github.com/ory/fosite/context.go generated vendored Normal file
View File

@ -0,0 +1,28 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package fosite
import "context"
func NewContext() context.Context {
return context.Background()
}

319
vendor/github.com/ory/fosite/errors.go generated vendored Normal file
View File

@ -0,0 +1,319 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package fosite
import (
"fmt"
"net/http"
"github.com/pkg/errors"
)
var (
// ErrInvalidatedAuthorizeCode is an error indicating that an authorization code has been
// used previously.
ErrInvalidatedAuthorizeCode = errors.New("Authorization code has ben invalidated")
// ErrSerializationFailure is an error indicating that the transactional capable storage could not guarantee
// consistency of Update & Delete operations on the same rows between multiple sessions.
ErrSerializationFailure = errors.New("The request could not be completed due to concurrent access")
ErrUnknownRequest = &RFC6749Error{
Name: errUnknownErrorName,
Description: "The handler is not responsible for this request",
Code: http.StatusBadRequest,
}
ErrRequestForbidden = &RFC6749Error{
Name: errRequestForbidden,
Description: "The request is not allowed",
Hint: "You are not allowed to perform this action.",
Code: http.StatusForbidden,
}
ErrInvalidRequest = &RFC6749Error{
Name: errInvalidRequestName,
Description: "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed",
Hint: "Make sure that the various parameters are correct, be aware of case sensitivity and trim your parameters. Make sure that the client you are using has exactly whitelisted the redirect_uri you specified.",
Code: http.StatusBadRequest,
}
ErrUnauthorizedClient = &RFC6749Error{
Name: errUnauthorizedClientName,
Description: "The client is not authorized to request a token using this method",
Hint: "Make sure that client id and secret are correctly specified and that the client exists.",
Code: http.StatusBadRequest,
}
ErrAccessDenied = &RFC6749Error{
Name: errAccessDeniedName,
Description: "The resource owner or authorization server denied the request",
Hint: "Make sure that the request you are making is valid. Maybe the credential or request parameters you are using are limited in scope or otherwise restricted.",
Code: http.StatusForbidden,
}
ErrUnsupportedResponseType = &RFC6749Error{
Name: errUnsupportedResponseTypeName,
Description: "The authorization server does not support obtaining a token using this method",
Code: http.StatusBadRequest,
}
ErrInvalidScope = &RFC6749Error{
Name: errInvalidScopeName,
Description: "The requested scope is invalid, unknown, or malformed",
Code: http.StatusBadRequest,
}
ErrServerError = &RFC6749Error{
Name: errServerErrorName,
Description: "The authorization server encountered an unexpected condition that prevented it from fulfilling the request",
Code: http.StatusInternalServerError,
}
ErrTemporarilyUnavailable = &RFC6749Error{
Name: errTemporarilyUnavailableName,
Description: "The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server",
Code: http.StatusServiceUnavailable,
}
ErrUnsupportedGrantType = &RFC6749Error{
Name: errUnsupportedGrantTypeName,
Description: "The authorization grant type is not supported by the authorization server",
Code: http.StatusBadRequest,
}
ErrInvalidGrant = &RFC6749Error{
Name: errInvalidGrantName,
Description: "The provided authorization grant (e.g., authorization code, resource owner credentials) or refresh token is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client",
Code: http.StatusBadRequest,
}
ErrInvalidClient = &RFC6749Error{
Name: errInvalidClientName,
Description: "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method)",
Code: http.StatusUnauthorized,
}
ErrInvalidState = &RFC6749Error{
Name: errInvalidStateName,
Description: fmt.Sprintf("The state is missing or has less than %d characters and is therefore considered too weak", MinParameterEntropy),
Code: http.StatusBadRequest,
}
ErrMisconfiguration = &RFC6749Error{
Name: errMisconfigurationName,
Description: "The request failed because of an internal error that is probably caused by misconfiguration",
Code: http.StatusInternalServerError,
}
ErrInsufficientEntropy = &RFC6749Error{
Name: errInsufficientEntropyName,
Description: fmt.Sprintf("The request used a security parameter (e.g., anti-replay, anti-csrf) with insufficient entropy (minimum of %d characters)", MinParameterEntropy),
Code: http.StatusBadRequest,
}
ErrNotFound = &RFC6749Error{
Name: errNotFoundName,
Description: "Could not find the requested resource(s)",
Code: http.StatusNotFound,
}
ErrRequestUnauthorized = &RFC6749Error{
Name: errRequestUnauthorizedName,
Description: "The request could not be authorized",
Hint: "Check that you provided valid credentials in the right format.",
Code: http.StatusUnauthorized,
}
ErrTokenSignatureMismatch = &RFC6749Error{
Name: errTokenSignatureMismatchName,
Description: "Token signature mismatch",
Hint: "Check that you provided a valid token in the right format.",
Code: http.StatusBadRequest,
}
ErrInvalidTokenFormat = &RFC6749Error{
Name: errInvalidTokenFormatName,
Description: "Invalid token format",
Hint: "Check that you provided a valid token in the right format.",
Code: http.StatusBadRequest,
}
ErrTokenExpired = &RFC6749Error{
Name: errTokenExpiredName,
Description: "Token expired",
Hint: "The token expired.",
Code: http.StatusUnauthorized,
}
ErrScopeNotGranted = &RFC6749Error{
Name: errScopeNotGrantedName,
Description: "The token was not granted the requested scope",
Hint: "The resource owner did not grant the requested scope.",
Code: http.StatusForbidden,
}
ErrTokenClaim = &RFC6749Error{
Name: errTokenClaimName,
Description: "The token failed validation due to a claim mismatch",
Hint: "One or more token claims failed validation.",
Code: http.StatusUnauthorized,
}
ErrInactiveToken = &RFC6749Error{
Name: errTokenInactiveName,
Description: "Token is inactive because it is malformed, expired or otherwise invalid",
Hint: "Token validation failed.",
Code: http.StatusUnauthorized,
}
ErrRevokationClientMismatch = &RFC6749Error{
Name: errRevokationClientMismatchName,
Description: "Token was not issued to the client making the revokation request",
Code: http.StatusBadRequest,
}
ErrLoginRequired = &RFC6749Error{
Name: errLoginRequired,
Description: "The Authorization Server requires End-User authentication",
Code: http.StatusBadRequest,
}
ErrInteractionRequired = &RFC6749Error{
Description: "The Authorization Server requires End-User interaction of some form to proceed",
Name: errInteractionRequired,
Code: http.StatusBadRequest,
}
ErrConsentRequired = &RFC6749Error{
Description: "The Authorization Server requires End-User consent",
Name: errConsentRequired,
Code: http.StatusBadRequest,
}
ErrRequestNotSupported = &RFC6749Error{
Description: "The OP does not support use of the request parameter",
Name: errRequestNotSupportedName,
Code: http.StatusBadRequest,
}
ErrRequestURINotSupported = &RFC6749Error{
Description: "The OP does not support use of the request_uri parameter",
Name: errRequestURINotSupportedName,
Code: http.StatusBadRequest,
}
ErrRegistrationNotSupported = &RFC6749Error{
Description: "The OP does not support use of the registration parameter",
Name: errRegistrationNotSupportedName,
Code: http.StatusBadRequest,
}
ErrInvalidRequestURI = &RFC6749Error{
Description: "The request_uri in the Authorization Request returns an error or contains invalid data. ",
Name: errInvalidRequestURI,
Code: http.StatusBadRequest,
}
ErrInvalidRequestObject = &RFC6749Error{
Description: "The request parameter contains an invalid Request Object. ",
Name: errInvalidRequestObject,
Code: http.StatusBadRequest,
}
ErrJTIKnown = &RFC6749Error{
Description: "The jti was already used.",
Name: errJTIKnownName,
Code: http.StatusBadRequest,
}
)
const (
errInvalidRequestURI = "invalid_request_uri"
errInvalidRequestObject = "invalid_request_object"
errConsentRequired = "consent_required"
errInteractionRequired = "interaction_required"
errLoginRequired = "login_required"
errRequestUnauthorizedName = "request_unauthorized"
errRequestForbidden = "request_forbidden"
errInvalidRequestName = "invalid_request"
errUnauthorizedClientName = "unauthorized_client"
errAccessDeniedName = "access_denied"
errUnsupportedResponseTypeName = "unsupported_response_type"
errInvalidScopeName = "invalid_scope"
errServerErrorName = "server_error"
errTemporarilyUnavailableName = "temporarily_unavailable"
errUnsupportedGrantTypeName = "unsupported_grant_type"
errInvalidGrantName = "invalid_grant"
errInvalidClientName = "invalid_client"
errNotFoundName = "not_found"
errInvalidStateName = "invalid_state"
errMisconfigurationName = "misconfiguration"
errInsufficientEntropyName = "insufficient_entropy"
errInvalidTokenFormatName = "invalid_token"
errTokenSignatureMismatchName = "token_signature_mismatch"
errTokenExpiredName = "token_expired"
errScopeNotGrantedName = "scope_not_granted"
errTokenClaimName = "token_claim"
errTokenInactiveName = "token_inactive"
// errAuthorizaionCodeInactiveName = "authorization_code_inactive"
errUnknownErrorName = "error"
errRevokationClientMismatchName = "revokation_client_mismatch"
errRequestNotSupportedName = "request_not_supported"
errRequestURINotSupportedName = "request_uri_not_supported"
errRegistrationNotSupportedName = "registration_not_supported"
errJTIKnownName = "jti_known"
)
func ErrorToRFC6749Error(err error) *RFC6749Error {
if e, ok := err.(*RFC6749Error); ok {
return e
} else if e, ok := errors.Cause(err).(*RFC6749Error); ok {
return e
}
return &RFC6749Error{
Name: errUnknownErrorName,
Description: "The error is unrecognizable.",
Debug: err.Error(),
Code: http.StatusInternalServerError,
}
}
type RFC6749Error struct {
Name string `json:"error"`
Description string `json:"error_description"`
Hint string `json:"error_hint,omitempty"`
Code int `json:"status_code,omitempty"`
Debug string `json:"error_debug,omitempty"`
}
func (e *RFC6749Error) Status() string {
return http.StatusText(e.Code)
}
func (e *RFC6749Error) Error() string {
return e.Name
}
func (e *RFC6749Error) RequestID() string {
return ""
}
func (e *RFC6749Error) Reason() string {
return e.Hint
}
func (e *RFC6749Error) StatusCode() int {
return e.Code
}
func (e *RFC6749Error) WithHintf(hint string, args ...interface{}) *RFC6749Error {
return e.WithHint(fmt.Sprintf(hint, args...))
}
func (e *RFC6749Error) WithHint(hint string) *RFC6749Error {
err := *e
err.Hint = hint
return &err
}
func (e *RFC6749Error) WithDebug(debug string) *RFC6749Error {
err := *e
err.Debug = debug
return &err
}
func (e *RFC6749Error) WithDebugf(debug string, args ...interface{}) *RFC6749Error {
return e.WithDebug(fmt.Sprintf(debug, args...))
}
func (e *RFC6749Error) WithDescription(description string) *RFC6749Error {
err := *e
err.Description = description
return &err
}

105
vendor/github.com/ory/fosite/fosite.go generated vendored Normal file
View File

@ -0,0 +1,105 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package fosite
import (
"net/http"
"reflect"
)
// AuthorizeEndpointHandlers is a list of AuthorizeEndpointHandler
type AuthorizeEndpointHandlers []AuthorizeEndpointHandler
// Append adds an AuthorizeEndpointHandler to this list. Ignores duplicates based on reflect.TypeOf.
func (a *AuthorizeEndpointHandlers) Append(h AuthorizeEndpointHandler) {
for _, this := range *a {
if reflect.TypeOf(this) == reflect.TypeOf(h) {
return
}
}
*a = append(*a, h)
}
// TokenEndpointHandlers is a list of TokenEndpointHandler
type TokenEndpointHandlers []TokenEndpointHandler
// Append adds an TokenEndpointHandler to this list. Ignores duplicates based on reflect.TypeOf.
func (t *TokenEndpointHandlers) Append(h TokenEndpointHandler) {
for _, this := range *t {
if reflect.TypeOf(this) == reflect.TypeOf(h) {
return
}
}
*t = append(*t, h)
}
// TokenIntrospectionHandlers is a list of TokenValidator
type TokenIntrospectionHandlers []TokenIntrospector
// Append adds an AccessTokenValidator to this list. Ignores duplicates based on reflect.TypeOf.
func (t *TokenIntrospectionHandlers) Append(h TokenIntrospector) {
for _, this := range *t {
if reflect.TypeOf(this) == reflect.TypeOf(h) {
return
}
}
*t = append(*t, h)
}
// RevocationHandlers is a list of RevocationHandler
type RevocationHandlers []RevocationHandler
// Append adds an RevocationHandler to this list. Ignores duplicates based on reflect.TypeOf.
func (t *RevocationHandlers) Append(h RevocationHandler) {
for _, this := range *t {
if reflect.TypeOf(this) == reflect.TypeOf(h) {
return
}
}
*t = append(*t, h)
}
// Fosite implements OAuth2Provider.
type Fosite struct {
Store Storage
AuthorizeEndpointHandlers AuthorizeEndpointHandlers
TokenEndpointHandlers TokenEndpointHandlers
TokenIntrospectionHandlers TokenIntrospectionHandlers
RevocationHandlers RevocationHandlers
Hasher Hasher
ScopeStrategy ScopeStrategy
AudienceMatchingStrategy AudienceMatchingStrategy
JWKSFetcherStrategy JWKSFetcherStrategy
HTTPClient *http.Client
// TokenURL is the the URL of the Authorization Server's Token Endpoint.
TokenURL string
// SendDebugMessagesToClients if set to true, includes error debug messages in response payloads. Be aware that sensitive
// data may be exposed, depending on your implementation of Fosite. Such sensitive data might include database error
// codes or other information. Proceed with caution!
SendDebugMessagesToClients bool
}

BIN
vendor/github.com/ory/fosite/fosite.png generated vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

31
vendor/github.com/ory/fosite/generate-mocks.sh generated vendored Normal file
View File

@ -0,0 +1,31 @@
#!/bin/bash
mockgen -package internal -destination internal/hash.go github.com/ory/fosite Hasher
mockgen -package internal -destination internal/storage.go github.com/ory/fosite Storage
mockgen -package internal -destination internal/transactional.go github.com/ory/fosite/storage Transactional
mockgen -package internal -destination internal/oauth2_storage.go github.com/ory/fosite/handler/oauth2 CoreStorage
mockgen -package internal -destination internal/oauth2_strategy.go github.com/ory/fosite/handler/oauth2 CoreStrategy
mockgen -package internal -destination internal/authorize_code_storage.go github.com/ory/fosite/handler/oauth2 AuthorizeCodeStorage
mockgen -package internal -destination internal/access_token_storage.go github.com/ory/fosite/handler/oauth2 AccessTokenStorage
mockgen -package internal -destination internal/refresh_token_strategy.go github.com/ory/fosite/handler/oauth2 RefreshTokenStorage
mockgen -package internal -destination internal/oauth2_client_storage.go github.com/ory/fosite/handler/oauth2 ClientCredentialsGrantStorage
mockgen -package internal -destination internal/oauth2_owner_storage.go github.com/ory/fosite/handler/oauth2 ResourceOwnerPasswordCredentialsGrantStorage
mockgen -package internal -destination internal/oauth2_revoke_storage.go github.com/ory/fosite/handler/oauth2 TokenRevocationStorage
mockgen -package internal -destination internal/openid_id_token_storage.go github.com/ory/fosite/handler/openid OpenIDConnectRequestStorage
mockgen -package internal -destination internal/access_token_strategy.go github.com/ory/fosite/handler/oauth2 AccessTokenStrategy
mockgen -package internal -destination internal/refresh_token_strategy.go github.com/ory/fosite/handler/oauth2 RefreshTokenStrategy
mockgen -package internal -destination internal/authorize_code_strategy.go github.com/ory/fosite/handler/oauth2 AuthorizeCodeStrategy
mockgen -package internal -destination internal/id_token_strategy.go github.com/ory/fosite/handler/openid OpenIDConnectTokenStrategy
mockgen -package internal -destination internal/pkce_storage_strategy.go github.com/ory/fosite/handler/pkce PKCERequestStorage
mockgen -package internal -destination internal/authorize_handler.go github.com/ory/fosite AuthorizeEndpointHandler
mockgen -package internal -destination internal/revoke_handler.go github.com/ory/fosite RevocationHandler
mockgen -package internal -destination internal/token_handler.go github.com/ory/fosite TokenEndpointHandler
mockgen -package internal -destination internal/introspector.go github.com/ory/fosite TokenIntrospector
mockgen -package internal -destination internal/client.go github.com/ory/fosite Client
mockgen -package internal -destination internal/request.go github.com/ory/fosite Requester
mockgen -package internal -destination internal/access_request.go github.com/ory/fosite AccessRequester
mockgen -package internal -destination internal/access_response.go github.com/ory/fosite AccessResponder
mockgen -package internal -destination internal/authorize_request.go github.com/ory/fosite AuthorizeRequester
mockgen -package internal -destination internal/authorize_response.go github.com/ory/fosite AuthorizeResponder
goimports -w internal/

26
vendor/github.com/ory/fosite/go.mod generated vendored Normal file
View File

@ -0,0 +1,26 @@
module github.com/ory/fosite
require (
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/golang/mock v1.4.3
github.com/golang/protobuf v1.4.0 // indirect
github.com/gorilla/mux v1.7.0
github.com/magiconair/properties v1.8.1
github.com/mattn/goveralls v0.0.5
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
github.com/oleiade/reflections v1.0.0
github.com/ory/go-acc v0.2.1
github.com/ory/go-convenience v0.1.0
github.com/parnurzeal/gorequest v0.2.15
github.com/pborman/uuid v1.2.0
github.com/pkg/errors v0.8.1
github.com/stretchr/testify v1.4.0
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e // indirect
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
google.golang.org/appengine v1.6.5 // indirect
gopkg.in/square/go-jose.v2 v2.5.0
)
go 1.14

735
vendor/github.com/ory/fosite/go.sum generated vendored Normal file
View File

@ -0,0 +1,735 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.41.0/go.mod h1:OauMR7DV8fzvZIl2qg6rkaIhD/vmgk4iwEw/h6ercmg=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf h1:eg0MeVzsP1G42dRafH3vf+al2vQIJU0YHX+1Tw87oco=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/aws/aws-sdk-go v1.23.19/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-xray-sdk-go v0.9.4/go.mod h1:XtMKdBQfpVut+tJEwI7+dJFRxxRdxHDyVNp2tHXRq04=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cihub/seelog v0.0.0-20170130134532-f561c5e57575/go.mod h1:9d6lWj8KzO/fd/NrVaLscBKmPigpZpn5YawRPw+e3Yo=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dustin/go-humanize v0.0.0-20180713052910-9f541cc9db5d/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/elazarl/goproxy v0.0.0-20181003060214-f58a169a71a5 h1:LCoguo7Zd0MByKMbQbTvcZw7HiBcbvew+MOcwsJVwrY=
github.com/elazarl/goproxy v0.0.0-20181003060214-f58a169a71a5/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-bindata/go-bindata v3.1.1+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobuffalo/buffalo v0.12.8-0.20181004233540-fac9bb505aa8/go.mod h1:sLyT7/dceRXJUxSsE813JTQtA3Eb1vjxWfo/N//vXIY=
github.com/gobuffalo/buffalo v0.13.0/go.mod h1:Mjn1Ba9wpIbpbrD+lIDMy99pQ0H0LiddMIIDGse7qT4=
github.com/gobuffalo/buffalo-plugins v1.0.2/go.mod h1:pOp/uF7X3IShFHyobahTkTLZaeUXwb0GrUTb9ngJWTs=
github.com/gobuffalo/buffalo-plugins v1.0.4/go.mod h1:pWS1vjtQ6uD17MVFWf7i3zfThrEKWlI5+PYLw/NaDB4=
github.com/gobuffalo/buffalo-plugins v1.4.3/go.mod h1:uCzTY0woez4nDMdQjkcOYKanngeUVRO2HZi7ezmAjWY=
github.com/gobuffalo/buffalo-plugins v1.5.1/go.mod h1:jbmwSZK5+PiAP9cC09VQOrGMZFCa/P0UMlIS3O12r5w=
github.com/gobuffalo/buffalo-plugins v1.6.4/go.mod h1:/+N1aophkA2jZ1ifB2O3Y9yGwu6gKOVMtUmJnbg+OZI=
github.com/gobuffalo/buffalo-plugins v1.6.5/go.mod h1:0HVkbgrVs/MnPZ/FOseDMVanCTm2RNcdM0PuXcL1NNI=
github.com/gobuffalo/buffalo-plugins v1.6.7/go.mod h1:ZGZRkzz2PiKWHs0z7QsPBOTo2EpcGRArMEym6ghKYgk=
github.com/gobuffalo/buffalo-plugins v1.6.9/go.mod h1:yYlYTrPdMCz+6/+UaXg5Jm4gN3xhsvsQ2ygVatZV5vw=
github.com/gobuffalo/buffalo-plugins v1.6.11/go.mod h1:eAA6xJIL8OuynJZ8amXjRmHND6YiusVAaJdHDN1Lu8Q=
github.com/gobuffalo/buffalo-plugins v1.8.2/go.mod h1:9te6/VjEQ7pKp7lXlDIMqzxgGpjlKoAcAANdCgoR960=
github.com/gobuffalo/buffalo-plugins v1.8.3/go.mod h1:IAWq6vjZJVXebIq2qGTLOdlXzmpyTZ5iJG5b59fza5U=
github.com/gobuffalo/buffalo-plugins v1.9.4/go.mod h1:grCV6DGsQlVzQwk6XdgcL3ZPgLm9BVxlBmXPMF8oBHI=
github.com/gobuffalo/buffalo-plugins v1.10.0/go.mod h1:4osg8d9s60txLuGwXnqH+RCjPHj9K466cDFRl3PErHI=
github.com/gobuffalo/buffalo-plugins v1.11.0/go.mod h1:rtIvAYRjYibgmWhnjKmo7OadtnxuMG5ZQLr25ozAzjg=
github.com/gobuffalo/buffalo-pop v1.0.5/go.mod h1:Fw/LfFDnSmB/vvQXPvcXEjzP98Tc+AudyNWUBWKCwQ8=
github.com/gobuffalo/envy v1.6.4/go.mod h1:Abh+Jfw475/NWtYMEt+hnJWRiC8INKWibIMyNt1w2Mc=
github.com/gobuffalo/envy v1.6.5/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ=
github.com/gobuffalo/envy v1.6.6/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ=
github.com/gobuffalo/envy v1.6.7/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ=
github.com/gobuffalo/envy v1.6.8/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ=
github.com/gobuffalo/envy v1.6.9/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ=
github.com/gobuffalo/envy v1.6.10/go.mod h1:X0CFllQjTV5ogsnUrg+Oks2yTI+PU2dGYBJOEI2D1Uo=
github.com/gobuffalo/envy v1.6.11/go.mod h1:Fiq52W7nrHGDggFPhn2ZCcHw4u/rqXkqo+i7FB6EAcg=
github.com/gobuffalo/envy v1.6.12/go.mod h1:qJNrJhKkZpEW0glh5xP2syQHH5kgdmgsKss2Kk8PTP0=
github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
github.com/gobuffalo/events v1.0.3/go.mod h1:Txo8WmqScapa7zimEQIwgiJBvMECMe9gJjsKNPN3uZw=
github.com/gobuffalo/events v1.0.7/go.mod h1:z8txf6H9jWhQ5Scr7YPLWg/cgXBRj8Q4uYI+rsVCCSQ=
github.com/gobuffalo/events v1.0.8/go.mod h1:A5KyqT1sA+3GJiBE4QKZibse9mtOcI9nw8gGrDdqYGs=
github.com/gobuffalo/events v1.1.3/go.mod h1:9yPGWYv11GENtzrIRApwQRMYSbUgCsZ1w6R503fCfrk=
github.com/gobuffalo/events v1.1.4/go.mod h1:09/YRRgZHEOts5Isov+g9X2xajxdvOAcUuAHIX/O//A=
github.com/gobuffalo/events v1.1.5/go.mod h1:3YUSzgHfYctSjEjLCWbkXP6djH2M+MLaVRzb4ymbAK0=
github.com/gobuffalo/events v1.1.7/go.mod h1:6fGqxH2ing5XMb3EYRq9LEkVlyPGs4oO/eLzh+S8CxY=
github.com/gobuffalo/events v1.1.8/go.mod h1:UFy+W6X6VbCWS8k2iT81HYX65dMtiuVycMy04cplt/8=
github.com/gobuffalo/events v1.1.9/go.mod h1:/0nf8lMtP5TkgNbzYxR6Bl4GzBy5s5TebgNTdRfRbPM=
github.com/gobuffalo/fizz v1.0.12/go.mod h1:C0sltPxpYK8Ftvf64kbsQa2yiCZY4RZviurNxXdAKwc=
github.com/gobuffalo/flect v0.0.0-20180907193754-dc14d8acaf9f/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA=
github.com/gobuffalo/flect v0.0.0-20181002182613-4571df4b1daf/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA=
github.com/gobuffalo/flect v0.0.0-20181007231023-ae7ed6bfe683/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA=
github.com/gobuffalo/flect v0.0.0-20181018182602-fd24a256709f/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA=
github.com/gobuffalo/flect v0.0.0-20181019110701-3d6f0b585514/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA=
github.com/gobuffalo/flect v0.0.0-20181024204909-8f6be1a8c6c2/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA=
github.com/gobuffalo/flect v0.0.0-20181104133451-1f6e9779237a/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA=
github.com/gobuffalo/flect v0.0.0-20181114183036-47375f6d8328/go.mod h1:0HvNbHdfh+WOvDSIASqJOSxTOWSxCCUF++k/Y53v9rI=
github.com/gobuffalo/flect v0.0.0-20181210151238-24a2b68e0316/go.mod h1:en58vff74S9b99Eg42Dr+/9yPu437QjlNsO/hBYPuOk=
github.com/gobuffalo/flect v0.0.0-20190104192022-4af577e09bf2/go.mod h1:en58vff74S9b99Eg42Dr+/9yPu437QjlNsO/hBYPuOk=
github.com/gobuffalo/flect v0.0.0-20190117212819-a62e61d96794/go.mod h1:397QT6v05LkZkn07oJXXT6y9FCfwC8Pug0WA2/2mE9k=
github.com/gobuffalo/genny v0.0.0-20180924032338-7af3a40f2252/go.mod h1:tUTQOogrr7tAQnhajMSH6rv1BVev34H2sa1xNHMy94g=
github.com/gobuffalo/genny v0.0.0-20181003150629-3786a0744c5d/go.mod h1:WAd8HmjMVrnkAZbmfgH5dLBUchsZfqzp/WS5sQz+uTM=
github.com/gobuffalo/genny v0.0.0-20181005145118-318a41a134cc/go.mod h1:WAd8HmjMVrnkAZbmfgH5dLBUchsZfqzp/WS5sQz+uTM=
github.com/gobuffalo/genny v0.0.0-20181007153042-b8de7d566757/go.mod h1:+oG5Ljrw04czAHbPXREwaFojJbpUvcIy4DiOnbEJFTA=
github.com/gobuffalo/genny v0.0.0-20181012161047-33e5f43d83a6/go.mod h1:+oG5Ljrw04czAHbPXREwaFojJbpUvcIy4DiOnbEJFTA=
github.com/gobuffalo/genny v0.0.0-20181017160347-90a774534246/go.mod h1:+oG5Ljrw04czAHbPXREwaFojJbpUvcIy4DiOnbEJFTA=
github.com/gobuffalo/genny v0.0.0-20181024195656-51392254bf53/go.mod h1:o9GEH5gn5sCKLVB5rHFC4tq40rQ3VRUzmx6WwmaqISE=
github.com/gobuffalo/genny v0.0.0-20181025145300-af3f81d526b8/go.mod h1:uZ1fFYvdcP8mu0B/Ynarf6dsGvp7QFIpk/QACUuFUVI=
github.com/gobuffalo/genny v0.0.0-20181027191429-94d6cfb5c7fc/go.mod h1:x7SkrQQBx204Y+O9EwRXeszLJDTaWN0GnEasxgLrQTA=
github.com/gobuffalo/genny v0.0.0-20181027195209-3887b7171c4f/go.mod h1:JbKx8HSWICu5zyqWOa0dVV1pbbXOHusrSzQUprW6g+w=
github.com/gobuffalo/genny v0.0.0-20181106193839-7dcb0924caf1/go.mod h1:x61yHxvbDCgQ/7cOAbJCacZQuHgB0KMSzoYcw5debjU=
github.com/gobuffalo/genny v0.0.0-20181107223128-f18346459dbe/go.mod h1:utQD3aKKEsdb03oR+Vi/6ztQb1j7pO10N3OBoowRcSU=
github.com/gobuffalo/genny v0.0.0-20181114215459-0a4decd77f5d/go.mod h1:kN2KZ8VgXF9VIIOj/GM0Eo7YK+un4Q3tTreKOf0q1ng=
github.com/gobuffalo/genny v0.0.0-20181119162812-e8ff4adce8bb/go.mod h1:BA9htSe4bZwBDJLe8CUkoqkypq3hn3+CkoHqVOW718E=
github.com/gobuffalo/genny v0.0.0-20181127225641-2d959acc795b/go.mod h1:l54xLXNkteX/PdZ+HlgPk1qtcrgeOr3XUBBPDbH+7CQ=
github.com/gobuffalo/genny v0.0.0-20181128191930-77e34f71ba2a/go.mod h1:FW/D9p7cEEOqxYA71/hnrkOWm62JZ5ZNxcNIVJEaWBU=
github.com/gobuffalo/genny v0.0.0-20181203165245-fda8bcce96b1/go.mod h1:wpNSANu9UErftfiaAlz1pDZclrYzLtO5lALifODyjuM=
github.com/gobuffalo/genny v0.0.0-20181203201232-849d2c9534ea/go.mod h1:wpNSANu9UErftfiaAlz1pDZclrYzLtO5lALifODyjuM=
github.com/gobuffalo/genny v0.0.0-20181206121324-d6fb8a0dbe36/go.mod h1:wpNSANu9UErftfiaAlz1pDZclrYzLtO5lALifODyjuM=
github.com/gobuffalo/genny v0.0.0-20181207164119-84844398a37d/go.mod h1:y0ysCHGGQf2T3vOhCrGHheYN54Y/REj0ayd0Suf4C/8=
github.com/gobuffalo/genny v0.0.0-20181211165820-e26c8466f14d/go.mod h1:sHnK+ZSU4e2feXP3PA29ouij6PUEiN+RCwECjCTB3yM=
github.com/gobuffalo/genny v0.0.0-20190104222617-a71664fc38e7/go.mod h1:QPsQ1FnhEsiU8f+O0qKWXz2RE4TiDqLVChWkBuh1WaY=
github.com/gobuffalo/genny v0.0.0-20190112155932-f31a84fcacf5/go.mod h1:CIaHCrSIuJ4il6ka3Hub4DR4adDrGoXGEEt2FbBxoIo=
github.com/gobuffalo/github_flavored_markdown v1.0.4/go.mod h1:uRowCdK+q8d/RF0Kt3/DSalaIXbb0De/dmTqMQdkQ4I=
github.com/gobuffalo/github_flavored_markdown v1.0.5/go.mod h1:U0643QShPF+OF2tJvYNiYDLDGDuQmJZXsf/bHOJPsMY=
github.com/gobuffalo/github_flavored_markdown v1.0.7/go.mod h1:w93Pd9Lz6LvyQXEG6DktTPHkOtCbr+arAD5mkwMzXLI=
github.com/gobuffalo/httptest v1.0.2/go.mod h1:7T1IbSrg60ankme0aDLVnEY0h056g9M1/ZvpVThtB7E=
github.com/gobuffalo/licenser v0.0.0-20180924033006-eae28e638a42/go.mod h1:Ubo90Np8gpsSZqNScZZkVXXAo5DGhTb+WYFIjlnog8w=
github.com/gobuffalo/licenser v0.0.0-20181025145548-437d89de4f75/go.mod h1:x3lEpYxkRG/XtGCUNkio+6RZ/dlOvLzTI9M1auIwFcw=
github.com/gobuffalo/licenser v0.0.0-20181027200154-58051a75da95/go.mod h1:BzhaaxGd1tq1+OLKObzgdCV9kqVhbTulxOpYbvMQWS0=
github.com/gobuffalo/licenser v0.0.0-20181109171355-91a2a7aac9a7/go.mod h1:m+Ygox92pi9bdg+gVaycvqE8RVSjZp7mWw75+K5NPHk=
github.com/gobuffalo/licenser v0.0.0-20181128165715-cc7305f8abed/go.mod h1:oU9F9UCE+AzI/MueCKZamsezGOOHfSirltllOVeRTAE=
github.com/gobuffalo/licenser v0.0.0-20181203160806-fe900bbede07/go.mod h1:ph6VDNvOzt1CdfaWC+9XwcBnlSTBz2j49PBwum6RFaU=
github.com/gobuffalo/licenser v0.0.0-20181211173111-f8a311c51159/go.mod h1:ve/Ue99DRuvnTaLq2zKa6F4KtHiYf7W046tDjuGYPfM=
github.com/gobuffalo/logger v0.0.0-20181022175615-46cfb361fc27/go.mod h1:8sQkgyhWipz1mIctHF4jTxmJh1Vxhp7mP8IqbljgJZo=
github.com/gobuffalo/logger v0.0.0-20181027144941-73d08d2bb969/go.mod h1:7uGg2duHKpWnN4+YmyKBdLXfhopkAdVM6H3nKbyFbz8=
github.com/gobuffalo/logger v0.0.0-20181027193913-9cf4dd0efe46/go.mod h1:7uGg2duHKpWnN4+YmyKBdLXfhopkAdVM6H3nKbyFbz8=
github.com/gobuffalo/logger v0.0.0-20181109185836-3feeab578c17/go.mod h1:oNErH0xLe+utO+OW8ptXMSA5DkiSEDW1u3zGIt8F9Ew=
github.com/gobuffalo/logger v0.0.0-20181117211126-8e9b89b7c264/go.mod h1:5etB91IE0uBlw9k756fVKZJdS+7M7ejVhmpXXiSFj0I=
github.com/gobuffalo/logger v0.0.0-20181127160119-5b956e21995c/go.mod h1:+HxKANrR9VGw9yN3aOAppJKvhO05ctDi63w4mDnKv2U=
github.com/gobuffalo/makr v1.1.5/go.mod h1:Y+o0btAH1kYAMDJW/TX3+oAXEu0bmSLLoC9mIFxtzOw=
github.com/gobuffalo/mapi v1.0.0/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
github.com/gobuffalo/meta v0.0.0-20181018155829-df62557efcd3/go.mod h1:XTTOhwMNryif3x9LkTTBO/Llrveezd71u3quLd0u7CM=
github.com/gobuffalo/meta v0.0.0-20181018192820-8c6cef77dab3/go.mod h1:E94EPzx9NERGCY69UWlcj6Hipf2uK/vnfrF4QD0plVE=
github.com/gobuffalo/meta v0.0.0-20181025145500-3a985a084b0a/go.mod h1:YDAKBud2FP7NZdruCSlmTmDOZbVSa6bpK7LJ/A/nlKg=
github.com/gobuffalo/meta v0.0.0-20181114191255-b130ebedd2f7/go.mod h1:K6cRZ29ozr4Btvsqkjvg5nDFTLOgTqf03KA70Ks0ypE=
github.com/gobuffalo/meta v0.0.0-20181127070345-0d7e59dd540b/go.mod h1:RLO7tMvE0IAKAM8wny1aN12pvEKn7EtkBLkUZR00Qf8=
github.com/gobuffalo/meta v0.0.0-20190120163247-50bbb1fa260d/go.mod h1:KKsH44nIK2gA8p0PJmRT9GvWJUdphkDUA8AJEvFWiqM=
github.com/gobuffalo/mw-basicauth v1.0.3/go.mod h1:dg7+ilMZOKnQFHDefUzUHufNyTswVUviCBgF244C1+0=
github.com/gobuffalo/mw-contenttype v0.0.0-20180802152300-74f5a47f4d56/go.mod h1:7EvcmzBbeCvFtQm5GqF9ys6QnCxz2UM1x0moiWLq1No=
github.com/gobuffalo/mw-csrf v0.0.0-20180802151833-446ff26e108b/go.mod h1:sbGtb8DmDZuDUQoxjr8hG1ZbLtZboD9xsn6p77ppcHo=
github.com/gobuffalo/mw-forcessl v0.0.0-20180802152810-73921ae7a130/go.mod h1:JvNHRj7bYNAMUr/5XMkZaDcw3jZhUZpsmzhd//FFWmQ=
github.com/gobuffalo/mw-i18n v0.0.0-20180802152014-e3060b7e13d6/go.mod h1:91AQfukc52A6hdfIfkxzyr+kpVYDodgAeT5cjX1UIj4=
github.com/gobuffalo/mw-paramlogger v0.0.0-20181005191442-d6ee392ec72e/go.mod h1:6OJr6VwSzgJMqWMj7TYmRUqzNe2LXu/W1rRW4MAz/ME=
github.com/gobuffalo/mw-tokenauth v0.0.0-20181001105134-8545f626c189/go.mod h1:UqBF00IfKvd39ni5+yI5MLMjAf4gX7cDKN/26zDOD6c=
github.com/gobuffalo/packd v0.0.0-20181027182251-01ad393492c8/go.mod h1:SmdBdhj6uhOsg1Ui4SFAyrhuc7U4VCildosO5IDJ3lc=
github.com/gobuffalo/packd v0.0.0-20181027190505-aafc0d02c411/go.mod h1:SmdBdhj6uhOsg1Ui4SFAyrhuc7U4VCildosO5IDJ3lc=
github.com/gobuffalo/packd v0.0.0-20181027194105-7ae579e6d213/go.mod h1:SmdBdhj6uhOsg1Ui4SFAyrhuc7U4VCildosO5IDJ3lc=
github.com/gobuffalo/packd v0.0.0-20181031195726-c82734870264/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI=
github.com/gobuffalo/packd v0.0.0-20181104210303-d376b15f8e96/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI=
github.com/gobuffalo/packd v0.0.0-20181111195323-b2e760a5f0ff/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI=
github.com/gobuffalo/packd v0.0.0-20181114190715-f25c5d2471d7/go.mod h1:Yf2toFaISlyQrr5TfO3h6DB9pl9mZRmyvBGQb/aQ/pI=
github.com/gobuffalo/packd v0.0.0-20181124090624-311c6248e5fb/go.mod h1:Foenia9ZvITEvG05ab6XpiD5EfBHPL8A6hush8SJ0o8=
github.com/gobuffalo/packd v0.0.0-20181207120301-c49825f8f6f4/go.mod h1:LYc0TGKFBBFTRC9dg2pcRcMqGCTMD7T2BIMP7OBuQAA=
github.com/gobuffalo/packd v0.0.0-20181212173646-eca3b8fd6687/go.mod h1:LYc0TGKFBBFTRC9dg2pcRcMqGCTMD7T2BIMP7OBuQAA=
github.com/gobuffalo/packr v1.13.7/go.mod h1:KkinLIn/n6+3tVXMwg6KkNvWwVsrRAz4ph+jgpk3Z24=
github.com/gobuffalo/packr v1.15.0/go.mod h1:t5gXzEhIviQwVlNx/+3SfS07GS+cZ2hn76WLzPp6MGI=
github.com/gobuffalo/packr v1.15.1/go.mod h1:IeqicJ7jm8182yrVmNbM6PR4g79SjN9tZLH8KduZZwE=
github.com/gobuffalo/packr v1.19.0/go.mod h1:MstrNkfCQhd5o+Ct4IJ0skWlxN8emOq8DsoT1G98VIU=
github.com/gobuffalo/packr v1.20.0/go.mod h1:JDytk1t2gP+my1ig7iI4NcVaXr886+N0ecUga6884zw=
github.com/gobuffalo/packr v1.21.0/go.mod h1:H00jGfj1qFKxscFJSw8wcL4hpQtPe1PfU2wa6sg/SR0=
github.com/gobuffalo/packr v1.22.0/go.mod h1:Qr3Wtxr3+HuQEwWqlLnNW4t1oTvK+7Gc/Rnoi/lDFvA=
github.com/gobuffalo/packr/v2 v2.0.0-rc.8/go.mod h1:y60QCdzwuMwO2R49fdQhsjCPv7tLQFR0ayzxxla9zes=
github.com/gobuffalo/packr/v2 v2.0.0-rc.9/go.mod h1:fQqADRfZpEsgkc7c/K7aMew3n4aF1Kji7+lIZeR98Fc=
github.com/gobuffalo/packr/v2 v2.0.0-rc.10/go.mod h1:4CWWn4I5T3v4c1OsJ55HbHlUEKNWMITG5iIkdr4Px4w=
github.com/gobuffalo/packr/v2 v2.0.0-rc.11/go.mod h1:JoieH/3h3U4UmatmV93QmqyPUdf4wVM9HELaHEu+3fk=
github.com/gobuffalo/packr/v2 v2.0.0-rc.12/go.mod h1:FV1zZTsVFi1DSCboO36Xgs4pzCZBjB/tDV9Cz/lSaR8=
github.com/gobuffalo/packr/v2 v2.0.0-rc.13/go.mod h1:2Mp7GhBFMdJlOK8vGfl7SYtfMP3+5roE39ejlfjw0rA=
github.com/gobuffalo/packr/v2 v2.0.0-rc.14/go.mod h1:06otbrNvDKO1eNQ3b8hst+1010UooI2MFg+B2Ze4MV8=
github.com/gobuffalo/packr/v2 v2.0.0-rc.15/go.mod h1:IMe7H2nJvcKXSF90y4X1rjYIRlNMJYCxEhssBXNZwWs=
github.com/gobuffalo/plush v3.7.16+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI=
github.com/gobuffalo/plush v3.7.20+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI=
github.com/gobuffalo/plush v3.7.21+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI=
github.com/gobuffalo/plush v3.7.22+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI=
github.com/gobuffalo/plush v3.7.23+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI=
github.com/gobuffalo/plush v3.7.30+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI=
github.com/gobuffalo/plush v3.7.31+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI=
github.com/gobuffalo/plush v3.7.32+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI=
github.com/gobuffalo/plushgen v0.0.0-20181128164830-d29dcb966cb2/go.mod h1:r9QwptTFnuvSaSRjpSp4S2/4e2D3tJhARYbvEBcKSb4=
github.com/gobuffalo/plushgen v0.0.0-20181203163832-9fc4964505c2/go.mod h1:opEdT33AA2HdrIwK1aibqnTJDVVKXC02Bar/GT1YRVs=
github.com/gobuffalo/plushgen v0.0.0-20181207152837-eedb135bd51b/go.mod h1:Lcw7HQbEVm09sAQrCLzIxuhFbB3nAgp4c55E+UlynR0=
github.com/gobuffalo/plushgen v0.0.0-20190104222512-177cd2b872b3/go.mod h1:tYxCozi8X62bpZyKXYHw1ncx2ZtT2nFvG42kuLwYjoc=
github.com/gobuffalo/pop v4.8.2+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg=
github.com/gobuffalo/pop v4.8.3+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg=
github.com/gobuffalo/pop v4.8.4+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg=
github.com/gobuffalo/release v1.0.35/go.mod h1:VtHFAKs61vO3wboCec5xr9JPTjYyWYcvaM3lclkc4x4=
github.com/gobuffalo/release v1.0.38/go.mod h1:VtHFAKs61vO3wboCec5xr9JPTjYyWYcvaM3lclkc4x4=
github.com/gobuffalo/release v1.0.42/go.mod h1:RPs7EtafH4oylgetOJpGP0yCZZUiO4vqHfTHJjSdpug=
github.com/gobuffalo/release v1.0.52/go.mod h1:RPs7EtafH4oylgetOJpGP0yCZZUiO4vqHfTHJjSdpug=
github.com/gobuffalo/release v1.0.53/go.mod h1:FdF257nd8rqhNaqtDWFGhxdJ/Ig4J7VcS3KL7n/a+aA=
github.com/gobuffalo/release v1.0.54/go.mod h1:Pe5/RxRa/BE8whDpGfRqSI7D1a0evGK1T4JDm339tJc=
github.com/gobuffalo/release v1.0.61/go.mod h1:mfIO38ujUNVDlBziIYqXquYfBF+8FDHUjKZgYC1Hj24=
github.com/gobuffalo/release v1.0.72/go.mod h1:NP5NXgg/IX3M5XmHmWR99D687/3Dt9qZtTK/Lbwc1hU=
github.com/gobuffalo/release v1.1.1/go.mod h1:Sluak1Xd6kcp6snkluR1jeXAogdJZpFFRzTYRs/2uwg=
github.com/gobuffalo/release v1.1.3/go.mod h1:CuXc5/m+4zuq8idoDt1l4va0AXAn/OSs08uHOfMVr8E=
github.com/gobuffalo/release v1.1.6/go.mod h1:18naWa3kBsqO0cItXZNJuefCKOENpbbUIqRL1g+p6z0=
github.com/gobuffalo/shoulders v1.0.1/go.mod h1:V33CcVmaQ4gRUmHKwq1fiTXuf8Gp/qjQBUL5tHPmvbA=
github.com/gobuffalo/syncx v0.0.0-20181120191700-98333ab04150/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
github.com/gobuffalo/syncx v0.0.0-20181120194010-558ac7de985f/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
github.com/gobuffalo/tags v2.0.11+incompatible/go.mod h1:9XmhOkyaB7UzvuY4UoZO4s67q8/xRMVJEaakauVQYeY=
github.com/gobuffalo/tags v2.0.14+incompatible/go.mod h1:9XmhOkyaB7UzvuY4UoZO4s67q8/xRMVJEaakauVQYeY=
github.com/gobuffalo/tags v2.0.15+incompatible/go.mod h1:9XmhOkyaB7UzvuY4UoZO4s67q8/xRMVJEaakauVQYeY=
github.com/gobuffalo/uuid v2.0.3+incompatible/go.mod h1:ErhIzkRhm0FtRuiE/PeORqcw4cVi1RtSpnwYrxuvkfE=
github.com/gobuffalo/uuid v2.0.4+incompatible/go.mod h1:ErhIzkRhm0FtRuiE/PeORqcw4cVi1RtSpnwYrxuvkfE=
github.com/gobuffalo/uuid v2.0.5+incompatible/go.mod h1:ErhIzkRhm0FtRuiE/PeORqcw4cVi1RtSpnwYrxuvkfE=
github.com/gobuffalo/validate v2.0.3+incompatible/go.mod h1:N+EtDe0J8252BgfzQUChBgfd6L93m9weay53EWFVsMM=
github.com/gobuffalo/x v0.0.0-20181003152136-452098b06085/go.mod h1:WevpGD+5YOreDJznWevcn8NTmQEW5STSBgIkpkjzqXc=
github.com/gobuffalo/x v0.0.0-20181007152206-913e47c59ca7/go.mod h1:9rDPXaB3kXdKWzMc4odGQQdG2e2DIEmANy5aSJ9yesY=
github.com/gofrs/uuid v3.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/gddo v0.0.0-20180828051604-96d2a289f41e/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4=
github.com/golang/gddo v0.0.0-20190904175337-72a348e765d2/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.0 h1:Jf4mxPC/ziBnoPIdpQdPJ9OeiomAUHLvxmPRSPH9m4s=
github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181004151105-1babbf986f6f h1:JJ2EP5vV3LAD2U1CxQtD7PTOO15Y96kXmKDz7TjxGHs=
github.com/gopherjs/gopherjs v0.0.0-20181004151105-1babbf986f6f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.2 h1:Pgr17XVTNXAk3q/r4CpKzC5xBM/qW1uVLV+IhRZpIIk=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.0 h1:tOSd0UKHQd6urX6ApfOn4XdBMY6Sh1MfxV3kmaazO+U=
github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.1.2/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmoiron/sqlx v0.0.0-20180614180643-0dae4fefe7c0/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
github.com/joho/godotenv v1.2.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE=
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/karrick/godirwalk v1.7.5/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34=
github.com/karrick/godirwalk v1.7.7/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34=
github.com/karrick/godirwalk v1.7.8/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/luna-duclos/instrumentedsql v1.1.2/go.mod h1:4LGbEqDnopzNAiyxPPDXhLspyunZxgPTMJBKtC6U0BQ=
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/markbates/deplist v1.0.4/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM=
github.com/markbates/deplist v1.0.5/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM=
github.com/markbates/going v1.0.2/go.mod h1:UWCk3zm0UKefHZ7l8BNqi26UyiEMniznk8naLdTcy6c=
github.com/markbates/grift v1.0.4/go.mod h1:wbmtW74veyx+cgfwFhlnnMWqhoz55rnHR47oMXzsyVs=
github.com/markbates/hmax v1.0.0/go.mod h1:cOkR9dktiESxIMu+65oc/r/bdY4bE8zZw3OLhLx0X2c=
github.com/markbates/inflect v1.0.0/go.mod h1:oTeZL2KHA7CUX6X+fovmK9OvIOFuqu0TwdQrZjLTh88=
github.com/markbates/inflect v1.0.1/go.mod h1:uv3UVNBe5qBIfCm8O8Q+DW+S1EopeyINj+Ikhc7rnCk=
github.com/markbates/inflect v1.0.3/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs=
github.com/markbates/inflect v1.0.4/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs=
github.com/markbates/oncer v0.0.0-20180924031910-e862a676800b/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
github.com/markbates/oncer v0.0.0-20180924034138-723ad0170a46/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
github.com/markbates/oncer v0.0.0-20181014194634-05fccaae8fc4/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
github.com/markbates/refresh v1.4.10/go.mod h1:NDPHvotuZmTmesXxr95C9bjlw1/0frJwtME2dzcVKhc=
github.com/markbates/safe v1.0.0/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
github.com/markbates/sigtx v1.0.0/go.mod h1:QF1Hv6Ic6Ca6W+T+DL0Y/ypborFKyvUY9HmuCD4VeTc=
github.com/markbates/willie v1.0.9/go.mod h1:fsrFVWl91+gXpx/6dv715j7i11fYPfZ9ZGfH0DQzY7w=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
github.com/mattn/goveralls v0.0.5 h1:spfq8AyZ0cCk57Za6/juJ5btQxeE1FaEGMdfcI+XO48=
github.com/mattn/goveralls v0.0.5/go.mod h1:Xg2LHi51faXLyKXwsndxiW6uxEEQT9+3sjGzzwU4xy0=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/monoculum/formam v0.0.0-20180901015400-4e68be1d79ba/go.mod h1:RKgILGEJq24YyJ2ban8EO0RUVSJlF1pGsEvoLEACr/Q=
github.com/moul/http2curl v0.0.0-20170919181001-9ac6cf4d929b h1:Pip12xNtMvEFUBF4f8/b5yRXj94LLrNdLWELfOr2KcY=
github.com/moul/http2curl v0.0.0-20170919181001-9ac6cf4d929b/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/oleiade/reflections v1.0.0 h1:0ir4pc6v8/PJ0yw5AEtMddfXpWBXg9cnG7SgSoJuCgY=
github.com/oleiade/reflections v1.0.0/go.mod h1:RbATFBbKYkVdqmSFtx13Bb/tVhR0lgOBXunWTZKeL4w=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs=
github.com/ory/fosite v0.29.0/go.mod h1:0atSZmXO7CAcs6NPMI/Qtot8tmZYj04Nddoold4S2h0=
github.com/ory/go-acc v0.0.0-20181118080137-ddc355013f90/go.mod h1:sxnvPCxChFuSmTJGj8FdMupeq1BezCiEpDjTUXQ4hf4=
github.com/ory/go-acc v0.2.1 h1:Pwcmwd/cSnwJsYN76+w3HU7oXeWFTkwj/KUj1qGDrVw=
github.com/ory/go-acc v0.2.1/go.mod h1:0omgy2aa3nDBJ45VAKeLHH8ccPBudxLeic4xiDRtug0=
github.com/ory/go-convenience v0.1.0 h1:zouLKfF2GoSGnJwGq+PE/nJAE6dj2Zj5QlTgmMTsTS8=
github.com/ory/go-convenience v0.1.0/go.mod h1:uEY/a60PL5c12nYz4V5cHY03IBmwIAEm8TWB0yn9KNs=
github.com/ory/gojsonreference v0.0.0-20190720135523-6b606c2d8ee8/go.mod h1:wsH1C4nIeeQClDtD5AH7kF1uTS6zWyqfjVDTmB0Em7A=
github.com/ory/gojsonschema v1.1.1-0.20190919112458-f254ca73d5e9/go.mod h1:BNZpdJgB74KOLSsWFvzw6roXg1I6O51WO8roMmW+T7Y=
github.com/ory/herodot v0.6.2/go.mod h1:3BOneqcyBsVybCPAJoi92KN2BpJHcmDqAMcAAaJiJow=
github.com/ory/viper v1.5.6/go.mod h1:TYmpFpKLxjQwvT4f0QPpkOn4sDXU1kDgAwJpgLYiQ28=
github.com/ory/x v0.0.85 h1:AslLr2Efv6f7AT1tzn0RuX+sOri6h74phSh5lSeMqC4=
github.com/ory/x v0.0.85/go.mod h1:s44V8t3xyjWZREcU+mWlp4h302rTuM4aLXcW+y5FbQ8=
github.com/parnurzeal/gorequest v0.2.15 h1:oPjDCsF5IkD4gUk6vIgsxYNaSgvAnIh1EJeROn3HdJU=
github.com/parnurzeal/gorequest v0.2.15/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE=
github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfSeg=
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.0.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rubenv/sql-migrate v0.0.0-20190212093014-1007f53448d7/go.mod h1:WS0rl9eEliYI8DPnr3TOwz4439pay+qNgzJoVya/DmY=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4=
github.com/santhosh-tekuri/jsonschema/v2 v2.1.0/go.mod h1:yzJzKUGV4RbWqWIBBP4wSOBqavX5saE02yirLS0OTyg=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/segmentio/analytics-go v3.0.1+incompatible/go.mod h1:C7CYBtQWk4vRk2RyLu0qOcbHJ18E3F1HV2C/8JvKN48=
github.com/segmentio/backo-go v0.0.0-20160424052352-204274ad699c/go.mod h1:kJ9mm9YmoWSkk+oQ+5Cj8DEoRCX2JT6As4kEtIIOp1M=
github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
github.com/shurcooL/highlight_go v0.0.0-20170515013102-78fb10f4a5f8/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
github.com/shurcooL/octicon v0.0.0-20180602230221-c42b0e3b24d9/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
github.com/sirupsen/logrus v1.1.0/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A=
github.com/sirupsen/logrus v1.1.1/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a h1:JSvGDIbmil4Ui/dDdFBExb7/cmkNjyX5F97oglmvCDo=
github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.0/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.2.1/go.mod h1:P4AexN0a+C9tGAnUFNwDMYYZv3pjFuvmeiMyKRaNVlI=
github.com/spf13/viper v1.3.1/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/subosito/gotenv v1.1.1/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tidwall/gjson v1.3.2/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls=
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/sjson v1.0.4/go.mod h1:bURseu1nuBkFpIES5cz6zBtjmYeOQmEESshn7VpF15Y=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g=
github.com/uber/jaeger-client-go v2.15.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-lib v1.5.0/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/unrolled/secure v0.0.0-20180918153822-f340ee86eb8b/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA=
github.com/unrolled/secure v0.0.0-20181005190816-ff9db2ff917f/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA=
github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180830192347-182538f80094/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181009213950-7c1a557ab941/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181015023909-0c41d7ab0a0e/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181024171144-74cb1d3d52f4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181025113841-85e1b3f9139a/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181106171534-e4dc69e5b2fd/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190102171810-8d7daa0c54b3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180816102801-aaf60122140d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180921000356-2f5d2388922f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180926154720-4dfa2610cdf3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181017193950-04a2e542c03f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181207154023-610586996380/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181003184128-c57b0facaced h1:4oqSq7eft7MdPKBGQK11X9WYUxmj6ZLgGTqYIbY1kyw=
golang.org/x/oauth2 v0.0.0-20181003184128-c57b0facaced/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180831094639-fa5fdf94c789/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180921163948-d47a0f339242/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180927150500-dad3d9fb7b6e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181005133103-4497e2df6f9e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181011152604-fa43e7bc11ba/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181022134430-8a28ead16f52/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181024145615-5cd93ef61a7c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181025063200-d989b31c8746/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026064943-731415f00dce/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181106135930-3a76605856fd/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181206074257-70b957f3b65e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190116161447-11f53e031339/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd h1:3x5uuvBgE6oaXJjCOvpCC1IpgJogqQ+PqGGU3ZxAgII=
golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181003024731-2f84ea8ef872/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181006002542-f60d9635b16a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181008205924-a2b3f7f249e9/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181013182035-5e66757b835f/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181017214349-06f26fdaaa28/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181024171208-a2dc47679d30/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181026183834-f60e5f99f081/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181105230042-78dc5bac0cac/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181107215632-34b416bd17b3/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181114190951-94339b83286c/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181119130350-139d099f6620/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181127195227-b4e97c0ed882/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181127232545-e782529d0ddd/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181203210056-e5f3ab76ea4b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181205224935-3576414c54a4/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181206194817-bcd4e47d0288/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181207183836-8bc39b988060/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181212172921-837e80568c09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190102213336-ca9055ed7d04/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190104182027-498d95493402/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190111214448-fc1d57b08d7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190118193359-16909d206f00/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262 h1:qsl9y/CJx34tuA7QCPNp86JNJe4spst6Ff8MjvPUdPg=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190711191110-9a621aea19f8/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
golang.org/x/tools v0.0.0-20200113040837-eac381796e91 h1:OOkytthzFBKHY5EfEgLUabprb0LtJVkQtNxAQ02+UE4=
golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0 h1:S0iUepdCWODXRvtE+gcRDd15L+k+k1AiHlMiMjefH24=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190626174449-989357319d63/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw=
gopkg.in/mail.v2 v2.0.0-20180731213649-a0242b2233b4/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/square/go-jose.v2 v2.1.9/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.5.0 h1:OZ4sdq+Y+SHfYB7vfthi1Ei8b0vkP8ZPQgUfUwdUSqo=
gopkg.in/square/go-jose.v2 v2.5.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

69
vendor/github.com/ory/fosite/handler.go generated vendored Normal file
View File

@ -0,0 +1,69 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package fosite
import (
"context"
)
type AuthorizeEndpointHandler interface {
// HandleAuthorizeRequest handles an authorize endpoint request. To extend the handler's capabilities, the http request
// is passed along, if further information retrieval is required. If the handler feels that he is not responsible for
// the authorize request, he must return nil and NOT modify session nor responder neither requester.
//
// The following spec is a good example of what HandleAuthorizeRequest should do.
// * https://tools.ietf.org/html/rfc6749#section-3.1.1
// response_type REQUIRED.
// The value MUST be one of "code" for requesting an
// authorization code as described by Section 4.1.1, "token" for
// requesting an access token (implicit grant) as described by
// Section 4.2.1, or a registered extension value as described by Section 8.4.
HandleAuthorizeEndpointRequest(ctx context.Context, requester AuthorizeRequester, responder AuthorizeResponder) error
}
type TokenEndpointHandler interface {
// PopulateTokenEndpointResponse is responsible for setting return values and should only be executed if
// the handler's HandleTokenEndpointRequest did not return ErrUnknownRequest.
PopulateTokenEndpointResponse(ctx context.Context, requester AccessRequester, responder AccessResponder) error
// HandleTokenEndpointRequest handles an authorize request. If the handler is not responsible for handling
// the request, this method should return ErrUnknownRequest and otherwise handle the request.
HandleTokenEndpointRequest(ctx context.Context, requester AccessRequester) error
}
// RevocationHandler is the interface that allows token revocation for an OAuth2.0 provider.
// https://tools.ietf.org/html/rfc7009
//
// RevokeToken is invoked after a new token revocation request is parsed.
//
// https://tools.ietf.org/html/rfc7009#section-2.1
// If the particular
// token is a refresh token and the authorization server supports the
// revocation of access tokens, then the authorization server SHOULD
// also invalidate all access tokens based on the same authorization
// grant (see Implementation Note). If the token passed to the request
// is an access token, the server MAY revoke the respective refresh
// token as well.
type RevocationHandler interface {
// RevokeToken handles access and refresh token revocation.
RevokeToken(ctx context.Context, token string, tokenType TokenType, client Client) error
}

View File

@ -0,0 +1,129 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package oauth2
import (
"context"
"net/url"
"strings"
"time"
"github.com/pkg/errors"
"github.com/ory/fosite"
)
// AuthorizeExplicitGrantTypeHandler is a response handler for the Authorize Code grant using the explicit grant type
// as defined in https://tools.ietf.org/html/rfc6749#section-4.1
type AuthorizeExplicitGrantHandler struct {
AccessTokenStrategy AccessTokenStrategy
RefreshTokenStrategy RefreshTokenStrategy
AuthorizeCodeStrategy AuthorizeCodeStrategy
CoreStorage CoreStorage
//TokenRevocationStorage TokenRevocationStorage
// AuthCodeLifespan defines the lifetime of an authorize code.
AuthCodeLifespan time.Duration
// AccessTokenLifespan defines the lifetime of an access token.
AccessTokenLifespan time.Duration
// RefreshTokenLifespan defines the lifetime of a refresh token. Leave to 0 for unlimited lifetime.
RefreshTokenLifespan time.Duration
ScopeStrategy fosite.ScopeStrategy
AudienceMatchingStrategy fosite.AudienceMatchingStrategy
// SanitationWhiteList is a whitelist of form values that are required by the token endpoint. These values
// are safe for storage in a database (cleartext).
SanitationWhiteList []string
TokenRevocationStorage TokenRevocationStorage
IsRedirectURISecure func(*url.URL) bool
RefreshTokenScopes []string
}
func (c *AuthorizeExplicitGrantHandler) secureChecker() func(*url.URL) bool {
if c.IsRedirectURISecure == nil {
c.IsRedirectURISecure = fosite.IsRedirectURISecure
}
return c.IsRedirectURISecure
}
func (c *AuthorizeExplicitGrantHandler) HandleAuthorizeEndpointRequest(ctx context.Context, ar fosite.AuthorizeRequester, resp fosite.AuthorizeResponder) error {
// This let's us define multiple response types, for example open id connect's id_token
if !ar.GetResponseTypes().ExactOne("code") {
return nil
}
// Disabled because this is already handled at the authorize_request_handler
// if !ar.GetClient().GetResponseTypes().Has("code") {
// return errors.WithStack(fosite.ErrInvalidGrant)
// }
if !c.secureChecker()(ar.GetRedirectURI()) {
return errors.WithStack(fosite.ErrInvalidRequest.WithHint("Redirect URL is using an insecure protocol, http is only allowed for hosts with suffix `localhost`, for example: http://myapp.localhost/."))
}
client := ar.GetClient()
for _, scope := range ar.GetRequestedScopes() {
if !c.ScopeStrategy(client.GetScopes(), scope) {
return errors.WithStack(fosite.ErrInvalidScope.WithHintf("The OAuth 2.0 Client is not allowed to request scope \"%s\".", scope))
}
}
if err := c.AudienceMatchingStrategy(client.GetAudience(), ar.GetRequestedAudience()); err != nil {
return err
}
return c.IssueAuthorizeCode(ctx, ar, resp)
}
func (c *AuthorizeExplicitGrantHandler) IssueAuthorizeCode(ctx context.Context, ar fosite.AuthorizeRequester, resp fosite.AuthorizeResponder) error {
code, signature, err := c.AuthorizeCodeStrategy.GenerateAuthorizeCode(ctx, ar)
if err != nil {
return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error()))
}
ar.GetSession().SetExpiresAt(fosite.AuthorizeCode, time.Now().UTC().Add(c.AuthCodeLifespan))
if err := c.CoreStorage.CreateAuthorizeCodeSession(ctx, signature, ar.Sanitize(c.GetSanitationWhiteList())); err != nil {
return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error()))
}
resp.AddQuery("code", code)
resp.AddQuery("state", ar.GetState())
resp.AddQuery("scope", strings.Join(ar.GetGrantedScopes(), " "))
ar.SetResponseTypeHandled("code")
return nil
}
func (c *AuthorizeExplicitGrantHandler) GetSanitationWhiteList() []string {
if len(c.SanitationWhiteList) > 0 {
return c.SanitationWhiteList
}
return []string{
"code",
"redirect_uri",
}
}

View File

@ -0,0 +1,208 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package oauth2
import (
"context"
"time"
"github.com/ory/fosite/storage"
"github.com/pkg/errors"
"github.com/ory/fosite"
)
// HandleTokenEndpointRequest implements
// * https://tools.ietf.org/html/rfc6749#section-4.1.3 (everything)
func (c *AuthorizeExplicitGrantHandler) HandleTokenEndpointRequest(ctx context.Context, request fosite.AccessRequester) error {
// grant_type REQUIRED.
// Value MUST be set to "authorization_code".
if !request.GetGrantTypes().ExactOne("authorization_code") {
return errors.WithStack(errors.WithStack(fosite.ErrUnknownRequest))
}
if !request.GetClient().GetGrantTypes().Has("authorization_code") {
return errors.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client is not allowed to use authorization grant \"authorization_code\"."))
}
code := request.GetRequestForm().Get("code")
signature := c.AuthorizeCodeStrategy.AuthorizeCodeSignature(code)
authorizeRequest, err := c.CoreStorage.GetAuthorizeCodeSession(ctx, signature, request.GetSession())
if errors.Cause(err) == fosite.ErrInvalidatedAuthorizeCode {
if authorizeRequest == nil {
return fosite.ErrServerError.
WithHint("Misconfigured code lead to an error that prohibited the OAuth 2.0 Framework from processing this request.").
WithDebug("GetAuthorizeCodeSession must return a value for \"fosite.Requester\" when returning \"ErrInvalidatedAuthorizeCode\".")
}
//If an authorize code is used twice, we revoke all refresh and access tokens associated with this request.
reqID := authorizeRequest.GetID()
hint := "The authorization code has already been used."
debug := ""
if revErr := c.TokenRevocationStorage.RevokeAccessToken(ctx, reqID); revErr != nil {
hint += " Additionally, an error occurred during processing the access token revocation."
debug += "Revokation of access_token lead to error " + revErr.Error() + "."
}
if revErr := c.TokenRevocationStorage.RevokeRefreshToken(ctx, reqID); revErr != nil {
hint += " Additionally, an error occurred during processing the refresh token revocation."
debug += "Revokation of refresh_token lead to error " + revErr.Error() + "."
}
return errors.WithStack(fosite.ErrInvalidGrant.WithHint(hint).WithDebug(debug))
} else if err != nil && errors.Cause(err).Error() == fosite.ErrNotFound.Error() {
return errors.WithStack(fosite.ErrInvalidGrant.WithDebug(err.Error()))
} else if err != nil {
return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error()))
}
// The authorization server MUST verify that the authorization code is valid
// This needs to happen after store retrieval for the session to be hydrated properly
if err := c.AuthorizeCodeStrategy.ValidateAuthorizeCode(ctx, request, code); err != nil {
return errors.WithStack(fosite.ErrInvalidGrant.WithDebug(err.Error()))
}
// Override scopes
request.SetRequestedScopes(authorizeRequest.GetRequestedScopes())
// Override audiences
request.SetRequestedAudience(authorizeRequest.GetRequestedAudience())
// The authorization server MUST ensure that the authorization code was issued to the authenticated
// confidential client, or if the client is public, ensure that the
// code was issued to "client_id" in the request,
if authorizeRequest.GetClient().GetID() != request.GetClient().GetID() {
return errors.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client ID from this request does not match the one from the authorize request."))
}
// ensure that the "redirect_uri" parameter is present if the
// "redirect_uri" parameter was included in the initial authorization
// request as described in Section 4.1.1, and if included ensure that
// their values are identical.
forcedRedirectURI := authorizeRequest.GetRequestForm().Get("redirect_uri")
if forcedRedirectURI != "" && forcedRedirectURI != request.GetRequestForm().Get("redirect_uri") {
return errors.WithStack(fosite.ErrInvalidGrant.WithHint("The \"redirect_uri\" from this request does not match the one from the authorize request."))
}
// Checking of POST client_id skipped, because:
// If the client type is confidential or the client was issued client
// credentials (or assigned other authentication requirements), the
// client MUST authenticate with the authorization server as described
// in Section 3.2.1.
request.SetSession(authorizeRequest.GetSession())
request.SetID(authorizeRequest.GetID())
request.GetSession().SetExpiresAt(fosite.AccessToken, time.Now().UTC().Add(c.AccessTokenLifespan).Round(time.Second))
if c.RefreshTokenLifespan > -1 {
request.GetSession().SetExpiresAt(fosite.RefreshToken, time.Now().UTC().Add(c.RefreshTokenLifespan).Round(time.Second))
}
return nil
}
func canIssueRefreshToken(c *AuthorizeExplicitGrantHandler, request fosite.Requester) bool {
// Require one of the refresh token scopes, if set.
if len(c.RefreshTokenScopes) > 0 && !request.GetGrantedScopes().HasOneOf(c.RefreshTokenScopes...) {
return false
}
// Do not issue a refresh token to clients that cannot use the refresh token grant type.
if !request.GetClient().GetGrantTypes().Has("refresh_token") {
return false
}
return true
}
func (c *AuthorizeExplicitGrantHandler) PopulateTokenEndpointResponse(ctx context.Context, requester fosite.AccessRequester, responder fosite.AccessResponder) error {
// grant_type REQUIRED.
// Value MUST be set to "authorization_code", as this is the explicit grant handler.
if !requester.GetGrantTypes().ExactOne("authorization_code") {
return errors.WithStack(fosite.ErrUnknownRequest)
}
code := requester.GetRequestForm().Get("code")
signature := c.AuthorizeCodeStrategy.AuthorizeCodeSignature(code)
authorizeRequest, err := c.CoreStorage.GetAuthorizeCodeSession(ctx, signature, requester.GetSession())
if err != nil {
return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error()))
} else if err := c.AuthorizeCodeStrategy.ValidateAuthorizeCode(ctx, requester, code); err != nil {
// This needs to happen after store retrieval for the session to be hydrated properly
return errors.WithStack(fosite.ErrInvalidRequest.WithDebug(err.Error()))
}
for _, scope := range authorizeRequest.GetGrantedScopes() {
requester.GrantScope(scope)
}
for _, audience := range authorizeRequest.GetGrantedAudience() {
requester.GrantAudience(audience)
}
access, accessSignature, err := c.AccessTokenStrategy.GenerateAccessToken(ctx, requester)
if err != nil {
return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error()))
}
var refresh, refreshSignature string
if canIssueRefreshToken(c, authorizeRequest) {
refresh, refreshSignature, err = c.RefreshTokenStrategy.GenerateRefreshToken(ctx, requester)
if err != nil {
return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error()))
}
}
ctx, err = storage.MaybeBeginTx(ctx, c.CoreStorage)
if err != nil {
return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error()))
}
if err := c.CoreStorage.InvalidateAuthorizeCodeSession(ctx, signature); err != nil {
if rollBackTxnErr := storage.MaybeRollbackTx(ctx, c.CoreStorage); rollBackTxnErr != nil {
err = rollBackTxnErr
}
return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error()))
} else if err := c.CoreStorage.CreateAccessTokenSession(ctx, accessSignature, requester.Sanitize([]string{})); err != nil {
if rollBackTxnErr := storage.MaybeRollbackTx(ctx, c.CoreStorage); rollBackTxnErr != nil {
err = rollBackTxnErr
}
return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error()))
} else if refreshSignature != "" {
if err := c.CoreStorage.CreateRefreshTokenSession(ctx, refreshSignature, requester.Sanitize([]string{})); err != nil {
if rollBackTxnErr := storage.MaybeRollbackTx(ctx, c.CoreStorage); rollBackTxnErr != nil {
err = rollBackTxnErr
}
return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error()))
}
}
responder.SetAccessToken(access)
responder.SetTokenType("bearer")
responder.SetExpiresIn(getExpiresIn(requester, fosite.AccessToken, c.AccessTokenLifespan, time.Now().UTC()))
responder.SetScopes(requester.GetGrantedScopes())
if refresh != "" {
responder.SetExtra("refresh_token", refresh)
}
if err := storage.MaybeCommitTx(ctx, c.CoreStorage); err != nil {
return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error()))
}
return nil
}

View File

@ -0,0 +1,106 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package oauth2
import (
"context"
"strconv"
"strings"
"time"
"github.com/pkg/errors"
"github.com/ory/fosite"
)
// AuthorizeImplicitGrantTypeHandler is a response handler for the Authorize Code grant using the implicit grant type
// as defined in https://tools.ietf.org/html/rfc6749#section-4.2
type AuthorizeImplicitGrantTypeHandler struct {
AccessTokenStrategy AccessTokenStrategy
// AccessTokenStorage is used to persist session data across requests.
AccessTokenStorage AccessTokenStorage
// AccessTokenLifespan defines the lifetime of an access token.
AccessTokenLifespan time.Duration
ScopeStrategy fosite.ScopeStrategy
AudienceMatchingStrategy fosite.AudienceMatchingStrategy
}
func (c *AuthorizeImplicitGrantTypeHandler) HandleAuthorizeEndpointRequest(ctx context.Context, ar fosite.AuthorizeRequester, resp fosite.AuthorizeResponder) error {
// This let's us define multiple response types, for example open id connect's id_token
if !ar.GetResponseTypes().ExactOne("token") {
return nil
}
// Disabled because this is already handled at the authorize_request_handler
// if !ar.GetClient().GetResponseTypes().Has("token") {
// return errors.WithStack(fosite.ErrInvalidGrant.WithDebug("The client is not allowed to use response type token"))
// }
if !ar.GetClient().GetGrantTypes().Has("implicit") {
return errors.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client is not allowed to use the authorization grant \"implicit\"."))
}
client := ar.GetClient()
for _, scope := range ar.GetRequestedScopes() {
if !c.ScopeStrategy(client.GetScopes(), scope) {
return errors.WithStack(fosite.ErrInvalidScope.WithHintf("The OAuth 2.0 Client is not allowed to request scope \"%s\".", scope))
}
}
if err := c.AudienceMatchingStrategy(client.GetAudience(), ar.GetRequestedAudience()); err != nil {
return err
}
// there is no need to check for https, because implicit flow does not require https
// https://tools.ietf.org/html/rfc6819#section-4.4.2
return c.IssueImplicitAccessToken(ctx, ar, resp)
}
func (c *AuthorizeImplicitGrantTypeHandler) IssueImplicitAccessToken(ctx context.Context, ar fosite.AuthorizeRequester, resp fosite.AuthorizeResponder) error {
// Only override expiry if none is set.
if ar.GetSession().GetExpiresAt(fosite.AccessToken).IsZero() {
ar.GetSession().SetExpiresAt(fosite.AccessToken, time.Now().UTC().Add(c.AccessTokenLifespan).Round(time.Second))
}
// Generate the code
token, signature, err := c.AccessTokenStrategy.GenerateAccessToken(ctx, ar)
if err != nil {
return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error()))
}
if err := c.AccessTokenStorage.CreateAccessTokenSession(ctx, signature, ar.Sanitize([]string{})); err != nil {
return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error()))
}
resp.AddFragment("access_token", token)
resp.AddFragment("expires_in", strconv.FormatInt(int64(getExpiresIn(ar, fosite.AccessToken, c.AccessTokenLifespan, time.Now().UTC())/time.Second), 10))
resp.AddFragment("token_type", "bearer")
resp.AddFragment("state", ar.GetState())
resp.AddFragment("scope", strings.Join(ar.GetGrantedScopes(), " "))
ar.SetResponseTypeHandled("token")
return nil
}

View File

@ -0,0 +1,81 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package oauth2
import (
"context"
"time"
"github.com/pkg/errors"
"github.com/ory/fosite"
)
type ClientCredentialsGrantHandler struct {
*HandleHelper
ScopeStrategy fosite.ScopeStrategy
AudienceMatchingStrategy fosite.AudienceMatchingStrategy
}
// IntrospectTokenEndpointRequest implements https://tools.ietf.org/html/rfc6749#section-4.4.2
func (c *ClientCredentialsGrantHandler) HandleTokenEndpointRequest(_ context.Context, request fosite.AccessRequester) error {
// grant_type REQUIRED.
// Value MUST be set to "client_credentials".
if !request.GetGrantTypes().ExactOne("client_credentials") {
return errors.WithStack(fosite.ErrUnknownRequest)
}
client := request.GetClient()
for _, scope := range request.GetRequestedScopes() {
if !c.ScopeStrategy(client.GetScopes(), scope) {
return errors.WithStack(fosite.ErrInvalidScope.WithHintf("The OAuth 2.0 Client is not allowed to request scope \"%s\".", scope))
}
}
if err := c.AudienceMatchingStrategy(client.GetAudience(), request.GetRequestedAudience()); err != nil {
return err
}
// The client MUST authenticate with the authorization server as described in Section 3.2.1.
// This requirement is already fulfilled because fosite requires all token requests to be authenticated as described
// in https://tools.ietf.org/html/rfc6749#section-3.2.1
if client.IsPublic() {
return errors.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client is marked as public and is thus not allowed to use authorization grant \"client_credentials\"."))
}
// if the client is not public, he has already been authenticated by the access request handler.
request.GetSession().SetExpiresAt(fosite.AccessToken, time.Now().UTC().Add(c.AccessTokenLifespan))
return nil
}
// PopulateTokenEndpointResponse implements https://tools.ietf.org/html/rfc6749#section-4.4.3
func (c *ClientCredentialsGrantHandler) PopulateTokenEndpointResponse(ctx context.Context, request fosite.AccessRequester, response fosite.AccessResponder) error {
if !request.GetGrantTypes().ExactOne("client_credentials") {
return errors.WithStack(fosite.ErrUnknownRequest)
}
if !request.GetClient().GetGrantTypes().Has("client_credentials") {
return errors.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client is not allowed to use authorization grant \"client_credentials\"."))
}
return c.IssueAccessToken(ctx, request, response)
}

View File

@ -0,0 +1,26 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package oauth2
type ClientCredentialsGrantStorage interface {
AccessTokenStorage
}

View File

@ -0,0 +1,194 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package oauth2
import (
"context"
"fmt"
"strings"
"time"
"github.com/pkg/errors"
"github.com/ory/fosite"
"github.com/ory/fosite/storage"
)
type RefreshTokenGrantHandler struct {
AccessTokenStrategy AccessTokenStrategy
RefreshTokenStrategy RefreshTokenStrategy
TokenRevocationStorage TokenRevocationStorage
// AccessTokenLifespan defines the lifetime of an access token.
AccessTokenLifespan time.Duration
// RefreshTokenLifespan defines the lifetime of a refresh token.
RefreshTokenLifespan time.Duration
ScopeStrategy fosite.ScopeStrategy
AudienceMatchingStrategy fosite.AudienceMatchingStrategy
RefreshTokenScopes []string
}
// HandleTokenEndpointRequest implements https://tools.ietf.org/html/rfc6749#section-6
func (c *RefreshTokenGrantHandler) HandleTokenEndpointRequest(ctx context.Context, request fosite.AccessRequester) error {
// grant_type REQUIRED.
// Value MUST be set to "refresh_token".
if !request.GetGrantTypes().ExactOne("refresh_token") {
return errors.WithStack(fosite.ErrUnknownRequest)
}
if !request.GetClient().GetGrantTypes().Has("refresh_token") {
return errors.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client is not allowed to use authorization grant \"refresh_token\"."))
}
refresh := request.GetRequestForm().Get("refresh_token")
signature := c.RefreshTokenStrategy.RefreshTokenSignature(refresh)
originalRequest, err := c.TokenRevocationStorage.GetRefreshTokenSession(ctx, signature, request.GetSession())
if errors.Cause(err) == fosite.ErrNotFound {
return errors.WithStack(fosite.ErrInvalidGrant.WithDebugf("The refresh token has not been found: %s", err))
} else if err != nil {
return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error()))
} else if err := c.RefreshTokenStrategy.ValidateRefreshToken(ctx, originalRequest, refresh); err != nil {
// The authorization server MUST ... validate the refresh token.
// This needs to happen after store retrieval for the session to be hydrated properly
return errors.WithStack(fosite.ErrInvalidRequest.WithDebug(err.Error()))
}
if !(len(c.RefreshTokenScopes) == 0 || originalRequest.GetGrantedScopes().HasOneOf(c.RefreshTokenScopes...)) {
scopeNames := strings.Join(c.RefreshTokenScopes, " or ")
hint := fmt.Sprintf("The OAuth 2.0 Client was not granted scope %s and may thus not perform the \"refresh_token\" authorization grant.", scopeNames)
return errors.WithStack(fosite.ErrScopeNotGranted.WithHint(hint))
}
// The authorization server MUST ... and ensure that the refresh token was issued to the authenticated client
if originalRequest.GetClient().GetID() != request.GetClient().GetID() {
return errors.WithStack(fosite.ErrInvalidGrant.WithHint("The OAuth 2.0 Client ID from this request does not match the ID during the initial token issuance."))
}
request.SetSession(originalRequest.GetSession().Clone())
request.SetRequestedScopes(originalRequest.GetRequestedScopes())
request.SetRequestedAudience(originalRequest.GetRequestedAudience())
for _, scope := range originalRequest.GetGrantedScopes() {
if !c.ScopeStrategy(request.GetClient().GetScopes(), scope) {
return errors.WithStack(fosite.ErrInvalidScope.WithHintf("The OAuth 2.0 Client is not allowed to request scope \"%s\".", scope))
}
request.GrantScope(scope)
}
if err := c.AudienceMatchingStrategy(request.GetClient().GetAudience(), originalRequest.GetGrantedAudience()); err != nil {
return err
}
for _, audience := range originalRequest.GetGrantedAudience() {
request.GrantAudience(audience)
}
request.GetSession().SetExpiresAt(fosite.AccessToken, time.Now().UTC().Add(c.AccessTokenLifespan).Round(time.Second))
if c.RefreshTokenLifespan > -1 {
request.GetSession().SetExpiresAt(fosite.RefreshToken, time.Now().UTC().Add(c.RefreshTokenLifespan).Round(time.Second))
}
return nil
}
// PopulateTokenEndpointResponse implements https://tools.ietf.org/html/rfc6749#section-6
func (c *RefreshTokenGrantHandler) PopulateTokenEndpointResponse(ctx context.Context, requester fosite.AccessRequester, responder fosite.AccessResponder) error {
if !requester.GetGrantTypes().ExactOne("refresh_token") {
return errors.WithStack(fosite.ErrUnknownRequest)
}
accessToken, accessSignature, err := c.AccessTokenStrategy.GenerateAccessToken(ctx, requester)
if err != nil {
return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error()))
}
refreshToken, refreshSignature, err := c.RefreshTokenStrategy.GenerateRefreshToken(ctx, requester)
if err != nil {
return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error()))
}
signature := c.RefreshTokenStrategy.RefreshTokenSignature(requester.GetRequestForm().Get("refresh_token"))
ctx, err = storage.MaybeBeginTx(ctx, c.TokenRevocationStorage)
if err != nil {
return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error()))
}
ts, err := c.TokenRevocationStorage.GetRefreshTokenSession(ctx, signature, nil)
if err != nil {
return handleRefreshTokenEndpointResponseStorageError(ctx, true, c.TokenRevocationStorage, err)
} else if err := c.TokenRevocationStorage.RevokeAccessToken(ctx, ts.GetID()); err != nil {
return handleRefreshTokenEndpointResponseStorageError(ctx, true, c.TokenRevocationStorage, err)
} else if err := c.TokenRevocationStorage.RevokeRefreshToken(ctx, ts.GetID()); err != nil {
return handleRefreshTokenEndpointResponseStorageError(ctx, true, c.TokenRevocationStorage, err)
}
storeReq := requester.Sanitize([]string{})
storeReq.SetID(ts.GetID())
if err := c.TokenRevocationStorage.CreateAccessTokenSession(ctx, accessSignature, storeReq); err != nil {
return handleRefreshTokenEndpointResponseStorageError(ctx, true, c.TokenRevocationStorage, err)
}
if err := c.TokenRevocationStorage.CreateRefreshTokenSession(ctx, refreshSignature, storeReq); err != nil {
return handleRefreshTokenEndpointResponseStorageError(ctx, true, c.TokenRevocationStorage, err)
}
responder.SetAccessToken(accessToken)
responder.SetTokenType("bearer")
responder.SetExpiresIn(getExpiresIn(requester, fosite.AccessToken, c.AccessTokenLifespan, time.Now().UTC()))
responder.SetScopes(requester.GetGrantedScopes())
responder.SetExtra("refresh_token", refreshToken)
if err := storage.MaybeCommitTx(ctx, c.TokenRevocationStorage); err != nil {
return handleRefreshTokenEndpointResponseStorageError(ctx, false, c.TokenRevocationStorage, err)
}
return nil
}
func handleRefreshTokenEndpointResponseStorageError(ctx context.Context, rollback bool, store TokenRevocationStorage, storageErr error) (err error) {
defer func() {
if rollback {
if rbErr := storage.MaybeRollbackTx(ctx, store); rbErr != nil {
err = errors.WithStack(fosite.ErrServerError.WithDebug(rbErr.Error()))
}
}
}()
if errors.Cause(storageErr) == fosite.ErrSerializationFailure {
return errors.WithStack(fosite.ErrInvalidRequest.
WithDebugf(storageErr.Error()).
WithHint("Failed to refresh token because of multiple concurrent requests using the same token which is not allowed."))
}
if errors.Cause(storageErr) == fosite.ErrNotFound {
return errors.WithStack(fosite.ErrInvalidRequest.
WithDebugf(storageErr.Error()).
WithHint("Failed to refresh token because of multiple concurrent requests using the same token which is not allowed."))
}
return errors.WithStack(fosite.ErrServerError.WithDebug(storageErr.Error()))
}

View File

@ -0,0 +1,115 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package oauth2
import (
"context"
"time"
"github.com/pkg/errors"
"github.com/ory/fosite"
)
type ResourceOwnerPasswordCredentialsGrantHandler struct {
// ResourceOwnerPasswordCredentialsGrantStorage is used to persist session data across requests.
ResourceOwnerPasswordCredentialsGrantStorage ResourceOwnerPasswordCredentialsGrantStorage
RefreshTokenStrategy RefreshTokenStrategy
ScopeStrategy fosite.ScopeStrategy
AudienceMatchingStrategy fosite.AudienceMatchingStrategy
RefreshTokenScopes []string
*HandleHelper
}
// HandleTokenEndpointRequest implements https://tools.ietf.org/html/rfc6749#section-4.3.2
func (c *ResourceOwnerPasswordCredentialsGrantHandler) HandleTokenEndpointRequest(ctx context.Context, request fosite.AccessRequester) error {
// grant_type REQUIRED.
// Value MUST be set to "password".
if !request.GetGrantTypes().ExactOne("password") {
return errors.WithStack(fosite.ErrUnknownRequest)
}
if !request.GetClient().GetGrantTypes().Has("password") {
return errors.WithStack(fosite.ErrInvalidGrant.WithHint("The client is not allowed to use authorization grant \"password\"."))
}
client := request.GetClient()
for _, scope := range request.GetRequestedScopes() {
if !c.ScopeStrategy(client.GetScopes(), scope) {
return errors.WithStack(fosite.ErrInvalidScope.WithHintf("The OAuth 2.0 Client is not allowed to request scope \"%s\".", scope))
}
}
if err := c.AudienceMatchingStrategy(client.GetAudience(), request.GetRequestedAudience()); err != nil {
return err
}
username := request.GetRequestForm().Get("username")
password := request.GetRequestForm().Get("password")
if username == "" || password == "" {
return errors.WithStack(fosite.ErrInvalidRequest.WithHint("Username or password are missing from the POST body."))
} else if err := c.ResourceOwnerPasswordCredentialsGrantStorage.Authenticate(ctx, username, password); errors.Cause(err) == fosite.ErrNotFound {
return errors.WithStack(fosite.ErrRequestUnauthorized.WithHint("Unable to authenticate the provided username and password credentials.").WithDebug(err.Error()))
} else if err != nil {
return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error()))
}
// Credentials must not be passed around, potentially leaking to the database!
delete(request.GetRequestForm(), "password")
request.GetSession().SetExpiresAt(fosite.AccessToken, time.Now().UTC().Add(c.AccessTokenLifespan).Round(time.Second))
if c.RefreshTokenLifespan > -1 {
request.GetSession().SetExpiresAt(fosite.RefreshToken, time.Now().UTC().Add(c.RefreshTokenLifespan).Round(time.Second))
}
return nil
}
// PopulateTokenEndpointResponse implements https://tools.ietf.org/html/rfc6749#section-4.3.3
func (c *ResourceOwnerPasswordCredentialsGrantHandler) PopulateTokenEndpointResponse(ctx context.Context, requester fosite.AccessRequester, responder fosite.AccessResponder) error {
if !requester.GetGrantTypes().ExactOne("password") {
return errors.WithStack(fosite.ErrUnknownRequest)
}
var refresh, refreshSignature string
if len(c.RefreshTokenScopes) == 0 || requester.GetGrantedScopes().HasOneOf(c.RefreshTokenScopes...) {
var err error
refresh, refreshSignature, err = c.RefreshTokenStrategy.GenerateRefreshToken(ctx, requester)
if err != nil {
return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error()))
} else if err := c.ResourceOwnerPasswordCredentialsGrantStorage.CreateRefreshTokenSession(ctx, refreshSignature, requester.Sanitize([]string{})); err != nil {
return errors.WithStack(fosite.ErrServerError.WithDebug(err.Error()))
}
}
if err := c.IssueAccessToken(ctx, requester, responder); err != nil {
return err
}
if refresh != "" {
responder.SetExtra("refresh_token", refresh)
}
return nil
}

View File

@ -0,0 +1,32 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package oauth2
import (
"context"
)
type ResourceOwnerPasswordCredentialsGrantStorage interface {
Authenticate(ctx context.Context, name string, secret string) error
AccessTokenStorage
RefreshTokenStorage
}

58
vendor/github.com/ory/fosite/handler/oauth2/helper.go generated vendored Normal file
View File

@ -0,0 +1,58 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package oauth2
import (
"context"
"time"
"github.com/ory/fosite"
)
type HandleHelper struct {
AccessTokenStrategy AccessTokenStrategy
AccessTokenStorage AccessTokenStorage
AccessTokenLifespan time.Duration
RefreshTokenLifespan time.Duration
}
func (h *HandleHelper) IssueAccessToken(ctx context.Context, requester fosite.AccessRequester, responder fosite.AccessResponder) error {
token, signature, err := h.AccessTokenStrategy.GenerateAccessToken(ctx, requester)
if err != nil {
return err
} else if err := h.AccessTokenStorage.CreateAccessTokenSession(ctx, signature, requester.Sanitize([]string{})); err != nil {
return err
}
responder.SetAccessToken(token)
responder.SetTokenType("bearer")
responder.SetExpiresIn(getExpiresIn(requester, fosite.AccessToken, h.AccessTokenLifespan, time.Now().UTC()))
responder.SetScopes(requester.GetGrantedScopes())
return nil
}
func getExpiresIn(r fosite.Requester, key fosite.TokenType, defaultLifespan time.Duration, now time.Time) time.Duration {
if r.GetSession().GetExpiresAt(key).IsZero() {
return defaultLifespan
}
return time.Duration(r.GetSession().GetExpiresAt(key).UnixNano() - now.UnixNano())
}

View File

@ -0,0 +1,114 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package oauth2
import (
"context"
"github.com/pkg/errors"
"github.com/ory/fosite"
)
type CoreValidator struct {
CoreStrategy
CoreStorage
ScopeStrategy fosite.ScopeStrategy
DisableRefreshTokenValidation bool
}
func (c *CoreValidator) IntrospectToken(ctx context.Context, token string, tokenType fosite.TokenType, accessRequest fosite.AccessRequester, scopes []string) (fosite.TokenType, error) {
if c.DisableRefreshTokenValidation {
if err := c.introspectAccessToken(ctx, token, accessRequest, scopes); err != nil {
return "", err
}
return fosite.AccessToken, nil
}
var err error
switch tokenType {
case fosite.RefreshToken:
if err = c.introspectRefreshToken(ctx, token, accessRequest, scopes); err == nil {
return fosite.RefreshToken, nil
} else if err = c.introspectAccessToken(ctx, token, accessRequest, scopes); err == nil {
return fosite.AccessToken, nil
}
return "", err
}
if err = c.introspectAccessToken(ctx, token, accessRequest, scopes); err == nil {
return fosite.AccessToken, nil
} else if err := c.introspectRefreshToken(ctx, token, accessRequest, scopes); err == nil {
return fosite.RefreshToken, nil
}
return "", err
}
func matchScopes(ss fosite.ScopeStrategy, granted, scopes []string) error {
for _, scope := range scopes {
if scope == "" {
continue
}
if !ss(granted, scope) {
return errors.WithStack(fosite.ErrInvalidScope.WithHintf("The request scope \"%s\" has not been granted or is not allowed to be requested.", scope))
}
}
return nil
}
func (c *CoreValidator) introspectAccessToken(ctx context.Context, token string, accessRequest fosite.AccessRequester, scopes []string) error {
sig := c.CoreStrategy.AccessTokenSignature(token)
or, err := c.CoreStorage.GetAccessTokenSession(ctx, sig, accessRequest.GetSession())
if err != nil {
return errors.WithStack(fosite.ErrRequestUnauthorized.WithDebug(err.Error()))
} else if err := c.CoreStrategy.ValidateAccessToken(ctx, or, token); err != nil {
return err
}
if err := matchScopes(c.ScopeStrategy, or.GetGrantedScopes(), scopes); err != nil {
return err
}
accessRequest.Merge(or)
return nil
}
func (c *CoreValidator) introspectRefreshToken(ctx context.Context, token string, accessRequest fosite.AccessRequester, scopes []string) error {
sig := c.CoreStrategy.RefreshTokenSignature(token)
or, err := c.CoreStorage.GetRefreshTokenSession(ctx, sig, accessRequest.GetSession())
if err != nil {
return errors.WithStack(fosite.ErrRequestUnauthorized.WithDebug(err.Error()))
} else if err := c.CoreStrategy.ValidateRefreshToken(ctx, or, token); err != nil {
return err
}
if err := matchScopes(c.ScopeStrategy, or.GetGrantedScopes(), scopes); err != nil {
return err
}
accessRequest.Merge(or)
return nil
}

View File

@ -0,0 +1,60 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package oauth2
import (
"context"
"github.com/pkg/errors"
"github.com/ory/fosite"
)
type JWTAccessTokenStrategy interface {
AccessTokenStrategy
JWTStrategy
}
type StatelessJWTValidator struct {
JWTAccessTokenStrategy
ScopeStrategy fosite.ScopeStrategy
}
func (v *StatelessJWTValidator) IntrospectToken(ctx context.Context, token string, tokenType fosite.TokenType, accessRequest fosite.AccessRequester, scopes []string) (fosite.TokenType, error) {
or, err := v.JWTAccessTokenStrategy.ValidateJWT(ctx, fosite.AccessToken, token)
if err != nil {
return "", err
}
for _, scope := range scopes {
if scope == "" {
continue
}
if !v.ScopeStrategy(or.GetGrantedScopes(), scope) {
return "", errors.WithStack(fosite.ErrInvalidScope)
}
}
accessRequest.Merge(or)
return "", nil
}

View File

@ -0,0 +1,77 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package oauth2
import (
"context"
"github.com/pkg/errors"
"github.com/ory/fosite"
)
type TokenRevocationHandler struct {
TokenRevocationStorage TokenRevocationStorage
RefreshTokenStrategy RefreshTokenStrategy
AccessTokenStrategy AccessTokenStrategy
}
// RevokeToken implements https://tools.ietf.org/html/rfc7009#section-2.1
// The token type hint indicates which token type check should be performed first.
func (r *TokenRevocationHandler) RevokeToken(ctx context.Context, token string, tokenType fosite.TokenType, client fosite.Client) error {
discoveryFuncs := []func() (request fosite.Requester, err error){
func() (request fosite.Requester, err error) {
// Refresh token
signature := r.RefreshTokenStrategy.RefreshTokenSignature(token)
return r.TokenRevocationStorage.GetRefreshTokenSession(ctx, signature, nil)
},
func() (request fosite.Requester, err error) {
// Access token
signature := r.AccessTokenStrategy.AccessTokenSignature(token)
return r.TokenRevocationStorage.GetAccessTokenSession(ctx, signature, nil)
},
}
// Token type hinting
if tokenType == fosite.AccessToken {
discoveryFuncs[0], discoveryFuncs[1] = discoveryFuncs[1], discoveryFuncs[0]
}
var ar fosite.Requester
var err error
if ar, err = discoveryFuncs[0](); err != nil {
ar, err = discoveryFuncs[1]()
}
if err != nil {
return err
}
if ar.GetClient().GetID() != client.GetID() {
return errors.WithStack(fosite.ErrRevokationClientMismatch)
}
requestID := ar.GetID()
r.TokenRevocationStorage.RevokeRefreshToken(ctx, requestID)
r.TokenRevocationStorage.RevokeAccessToken(ctx, requestID)
return nil
}

View File

@ -0,0 +1,49 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package oauth2
import (
"context"
)
// TokenRevocationStorage provides the storage implementation
// as specified in: https://tools.ietf.org/html/rfc7009
type TokenRevocationStorage interface {
RefreshTokenStorage
AccessTokenStorage
// RevokeRefreshToken revokes a refresh token as specified in:
// https://tools.ietf.org/html/rfc7009#section-2.1
// If the particular
// token is a refresh token and the authorization server supports the
// revocation of access tokens, then the authorization server SHOULD
// also invalidate all access tokens based on the same authorization
// grant (see Implementation Note).
RevokeRefreshToken(ctx context.Context, requestID string) error
// RevokeAccessToken revokes an access token as specified in:
// https://tools.ietf.org/html/rfc7009#section-2.1
// If the token passed to the request
// is an access token, the server MAY revoke the respective refresh
// token as well.
RevokeAccessToken(ctx context.Context, requestID string) error
}

68
vendor/github.com/ory/fosite/handler/oauth2/storage.go generated vendored Normal file
View File

@ -0,0 +1,68 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package oauth2
import (
"context"
"github.com/ory/fosite"
)
type CoreStorage interface {
AuthorizeCodeStorage
AccessTokenStorage
RefreshTokenStorage
}
// AuthorizeCodeStorage handles storage requests related to authorization codes.
type AuthorizeCodeStorage interface {
// GetAuthorizeCodeSession stores the authorization request for a given authorization code.
CreateAuthorizeCodeSession(ctx context.Context, code string, request fosite.Requester) (err error)
// GetAuthorizeCodeSession hydrates the session based on the given code and returns the authorization request.
// If the authorization code has been invalidated with `InvalidateAuthorizeCodeSession`, this
// method should return the ErrInvalidatedAuthorizeCode error.
//
// Make sure to also return the fosite.Requester value when returning the fosite.ErrInvalidatedAuthorizeCode error!
GetAuthorizeCodeSession(ctx context.Context, code string, session fosite.Session) (request fosite.Requester, err error)
// InvalidateAuthorizeCodeSession is called when an authorize code is being used. The state of the authorization
// code should be set to invalid and consecutive requests to GetAuthorizeCodeSession should return the
// ErrInvalidatedAuthorizeCode error.
InvalidateAuthorizeCodeSession(ctx context.Context, code string) (err error)
}
type AccessTokenStorage interface {
CreateAccessTokenSession(ctx context.Context, signature string, request fosite.Requester) (err error)
GetAccessTokenSession(ctx context.Context, signature string, session fosite.Session) (request fosite.Requester, err error)
DeleteAccessTokenSession(ctx context.Context, signature string) (err error)
}
type RefreshTokenStorage interface {
CreateRefreshTokenSession(ctx context.Context, signature string, request fosite.Requester) (err error)
GetRefreshTokenSession(ctx context.Context, signature string, session fosite.Session) (request fosite.Requester, err error)
DeleteRefreshTokenSession(ctx context.Context, signature string) (err error)
}

View File

@ -0,0 +1,56 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package oauth2
import (
"context"
"github.com/ory/fosite"
)
type CoreStrategy interface {
AccessTokenStrategy
RefreshTokenStrategy
AuthorizeCodeStrategy
}
type JWTStrategy interface {
ValidateJWT(ctx context.Context, tokenType fosite.TokenType, token string) (requester fosite.Requester, err error)
}
type AccessTokenStrategy interface {
AccessTokenSignature(token string) string
GenerateAccessToken(ctx context.Context, requester fosite.Requester) (token string, signature string, err error)
ValidateAccessToken(ctx context.Context, requester fosite.Requester, token string) (err error)
}
type RefreshTokenStrategy interface {
RefreshTokenSignature(token string) string
GenerateRefreshToken(ctx context.Context, requester fosite.Requester) (token string, signature string, err error)
ValidateRefreshToken(ctx context.Context, requester fosite.Requester, token string) (err error)
}
type AuthorizeCodeStrategy interface {
AuthorizeCodeSignature(token string) string
GenerateAuthorizeCode(ctx context.Context, requester fosite.Requester) (token string, signature string, err error)
ValidateAuthorizeCode(ctx context.Context, requester fosite.Requester, token string) (err error)
}

View File

@ -0,0 +1,96 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package oauth2
import (
"context"
"time"
"github.com/pkg/errors"
"github.com/ory/fosite"
enigma "github.com/ory/fosite/token/hmac"
)
type HMACSHAStrategy struct {
Enigma *enigma.HMACStrategy
AccessTokenLifespan time.Duration
RefreshTokenLifespan time.Duration
AuthorizeCodeLifespan time.Duration
}
func (h HMACSHAStrategy) AccessTokenSignature(token string) string {
return h.Enigma.Signature(token)
}
func (h HMACSHAStrategy) RefreshTokenSignature(token string) string {
return h.Enigma.Signature(token)
}
func (h HMACSHAStrategy) AuthorizeCodeSignature(token string) string {
return h.Enigma.Signature(token)
}
func (h HMACSHAStrategy) GenerateAccessToken(_ context.Context, _ fosite.Requester) (token string, signature string, err error) {
return h.Enigma.Generate()
}
func (h HMACSHAStrategy) ValidateAccessToken(_ context.Context, r fosite.Requester, token string) (err error) {
var exp = r.GetSession().GetExpiresAt(fosite.AccessToken)
if exp.IsZero() && r.GetRequestedAt().Add(h.AccessTokenLifespan).Before(time.Now().UTC()) {
return errors.WithStack(fosite.ErrTokenExpired.WithHintf("Access token expired at \"%s\".", r.GetRequestedAt().Add(h.AccessTokenLifespan)))
}
if !exp.IsZero() && exp.Before(time.Now().UTC()) {
return errors.WithStack(fosite.ErrTokenExpired.WithHintf("Access token expired at \"%s\".", exp))
}
return h.Enigma.Validate(token)
}
func (h HMACSHAStrategy) GenerateRefreshToken(_ context.Context, _ fosite.Requester) (token string, signature string, err error) {
return h.Enigma.Generate()
}
func (h HMACSHAStrategy) ValidateRefreshToken(_ context.Context, r fosite.Requester, token string) (err error) {
var exp = r.GetSession().GetExpiresAt(fosite.RefreshToken)
if exp.IsZero() {
// Unlimited lifetime
return h.Enigma.Validate(token)
}
if !exp.IsZero() && exp.Before(time.Now().UTC()) {
return errors.WithStack(fosite.ErrTokenExpired.WithHintf("Refresh token expired at \"%s\".", exp))
}
return h.Enigma.Validate(token)
}
func (h HMACSHAStrategy) GenerateAuthorizeCode(_ context.Context, _ fosite.Requester) (token string, signature string, err error) {
return h.Enigma.Generate()
}
func (h HMACSHAStrategy) ValidateAuthorizeCode(_ context.Context, r fosite.Requester, token string) (err error) {
var exp = r.GetSession().GetExpiresAt(fosite.AuthorizeCode)
if exp.IsZero() && r.GetRequestedAt().Add(h.AuthorizeCodeLifespan).Before(time.Now().UTC()) {
return errors.WithStack(fosite.ErrTokenExpired.WithHintf("Authorize code expired at \"%s\".", r.GetRequestedAt().Add(h.AuthorizeCodeLifespan)))
}
if !exp.IsZero() && exp.Before(time.Now().UTC()) {
return errors.WithStack(fosite.ErrTokenExpired.WithHintf("Authorize code expired at \"%s\".", exp))
}
return h.Enigma.Validate(token)
}

View File

@ -0,0 +1,176 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package oauth2
import (
"context"
"strings"
"time"
jwtx "github.com/dgrijalva/jwt-go"
"github.com/pkg/errors"
"github.com/ory/fosite"
"github.com/ory/fosite/token/jwt"
)
// DefaultJWTStrategy is a JWT RS256 strategy.
type DefaultJWTStrategy struct {
jwt.JWTStrategy
HMACSHAStrategy *HMACSHAStrategy
Issuer string
}
func (h DefaultJWTStrategy) signature(token string) string {
split := strings.Split(token, ".")
if len(split) != 3 {
return ""
}
return split[2]
}
func (h DefaultJWTStrategy) AccessTokenSignature(token string) string {
return h.signature(token)
}
func (h *DefaultJWTStrategy) GenerateAccessToken(ctx context.Context, requester fosite.Requester) (token string, signature string, err error) {
return h.generate(ctx, fosite.AccessToken, requester)
}
func (h *DefaultJWTStrategy) ValidateAccessToken(ctx context.Context, _ fosite.Requester, token string) error {
_, err := h.validate(ctx, token)
return err
}
func (h *DefaultJWTStrategy) ValidateJWT(ctx context.Context, tokenType fosite.TokenType, token string) (requester fosite.Requester, err error) {
t, err := h.validate(ctx, token)
if err != nil {
return nil, err
}
claims := jwt.JWTClaims{}
claims.FromMapClaims(t.Claims.(jwtx.MapClaims))
requester = &fosite.Request{
Client: &fosite.DefaultClient{},
RequestedAt: claims.IssuedAt,
Session: &JWTSession{
JWTClaims: &claims,
JWTHeader: &jwt.Headers{
Extra: make(map[string]interface{}),
},
ExpiresAt: map[fosite.TokenType]time.Time{
tokenType: claims.ExpiresAt,
},
Subject: claims.Subject,
},
RequestedScope: claims.Scope,
GrantedScope: claims.Scope,
}
return
}
func (h DefaultJWTStrategy) RefreshTokenSignature(token string) string {
return h.HMACSHAStrategy.RefreshTokenSignature(token)
}
func (h DefaultJWTStrategy) AuthorizeCodeSignature(token string) string {
return h.HMACSHAStrategy.AuthorizeCodeSignature(token)
}
func (h *DefaultJWTStrategy) GenerateRefreshToken(ctx context.Context, req fosite.Requester) (token string, signature string, err error) {
return h.HMACSHAStrategy.GenerateRefreshToken(ctx, req)
}
func (h *DefaultJWTStrategy) ValidateRefreshToken(ctx context.Context, req fosite.Requester, token string) error {
return h.HMACSHAStrategy.ValidateRefreshToken(ctx, req, token)
}
func (h *DefaultJWTStrategy) GenerateAuthorizeCode(ctx context.Context, req fosite.Requester) (token string, signature string, err error) {
return h.HMACSHAStrategy.GenerateAuthorizeCode(ctx, req)
}
func (h *DefaultJWTStrategy) ValidateAuthorizeCode(ctx context.Context, req fosite.Requester, token string) error {
return h.HMACSHAStrategy.ValidateAuthorizeCode(ctx, req, token)
}
func (h *DefaultJWTStrategy) validate(ctx context.Context, token string) (t *jwtx.Token, err error) {
t, err = h.JWTStrategy.Decode(ctx, token)
if err == nil {
err = t.Claims.Valid()
}
if err != nil {
if e, ok := errors.Cause(err).(*jwtx.ValidationError); ok {
switch e.Errors {
case jwtx.ValidationErrorMalformed:
err = errors.WithStack(fosite.ErrInvalidTokenFormat.WithDebug(err.Error()))
case jwtx.ValidationErrorUnverifiable:
err = errors.WithStack(fosite.ErrTokenSignatureMismatch.WithDebug(err.Error()))
case jwtx.ValidationErrorSignatureInvalid:
err = errors.WithStack(fosite.ErrTokenSignatureMismatch.WithDebug(err.Error()))
case jwtx.ValidationErrorAudience:
err = errors.WithStack(fosite.ErrTokenClaim.WithDebug(err.Error()))
case jwtx.ValidationErrorExpired:
err = errors.WithStack(fosite.ErrTokenExpired.WithDebug(err.Error()))
case jwtx.ValidationErrorIssuedAt:
err = errors.WithStack(fosite.ErrTokenClaim.WithDebug(err.Error()))
case jwtx.ValidationErrorIssuer:
err = errors.WithStack(fosite.ErrTokenClaim.WithDebug(err.Error()))
case jwtx.ValidationErrorNotValidYet:
err = errors.WithStack(fosite.ErrTokenClaim.WithDebug(err.Error()))
case jwtx.ValidationErrorId:
err = errors.WithStack(fosite.ErrTokenClaim.WithDebug(err.Error()))
case jwtx.ValidationErrorClaimsInvalid:
err = errors.WithStack(fosite.ErrTokenClaim.WithDebug(err.Error()))
default:
err = errors.WithStack(fosite.ErrRequestUnauthorized.WithDebug(err.Error()))
}
}
}
return
}
func (h *DefaultJWTStrategy) generate(ctx context.Context, tokenType fosite.TokenType, requester fosite.Requester) (string, string, error) {
if jwtSession, ok := requester.GetSession().(JWTSessionContainer); !ok {
return "", "", errors.Errorf("Session must be of type JWTSessionContainer but got type: %T", requester.GetSession())
} else if jwtSession.GetJWTClaims() == nil {
return "", "", errors.New("GetTokenClaims() must not be nil")
} else {
claims := jwtSession.GetJWTClaims().
With(
jwtSession.GetExpiresAt(tokenType),
requester.GetGrantedScopes(),
requester.GetGrantedAudience(),
).
WithDefaults(
time.Now().UTC(),
h.Issuer,
)
return h.JWTStrategy.Generate(ctx, claims.ToMapClaims(), jwtSession.GetJWTHeader())
}
}

View File

@ -0,0 +1,105 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package oauth2
import (
"time"
"github.com/mohae/deepcopy"
"github.com/ory/fosite"
"github.com/ory/fosite/token/jwt"
)
type JWTSessionContainer interface {
// GetJWTClaims returns the claims.
GetJWTClaims() jwt.JWTClaimsContainer
// GetJWTHeader returns the header.
GetJWTHeader() *jwt.Headers
fosite.Session
}
// JWTSession Container for the JWT session.
type JWTSession struct {
JWTClaims *jwt.JWTClaims
JWTHeader *jwt.Headers
ExpiresAt map[fosite.TokenType]time.Time
Username string
Subject string
}
func (j *JWTSession) GetJWTClaims() jwt.JWTClaimsContainer {
if j.JWTClaims == nil {
j.JWTClaims = &jwt.JWTClaims{}
}
return j.JWTClaims
}
func (j *JWTSession) GetJWTHeader() *jwt.Headers {
if j.JWTHeader == nil {
j.JWTHeader = &jwt.Headers{}
}
return j.JWTHeader
}
func (s *JWTSession) SetExpiresAt(key fosite.TokenType, exp time.Time) {
if s.ExpiresAt == nil {
s.ExpiresAt = make(map[fosite.TokenType]time.Time)
}
s.ExpiresAt[key] = exp
}
func (s *JWTSession) GetExpiresAt(key fosite.TokenType) time.Time {
if s.ExpiresAt == nil {
s.ExpiresAt = make(map[fosite.TokenType]time.Time)
}
if _, ok := s.ExpiresAt[key]; !ok {
return time.Time{}
}
return s.ExpiresAt[key]
}
func (s *JWTSession) GetUsername() string {
if s == nil {
return ""
}
return s.Username
}
func (s *JWTSession) GetSubject() string {
if s == nil {
return ""
}
return s.Subject
}
func (s *JWTSession) Clone() fosite.Session {
if s == nil {
return nil
}
return deepcopy.Copy(s).(fosite.Session)
}

28
vendor/github.com/ory/fosite/handler/openid/errors.go generated vendored Normal file
View File

@ -0,0 +1,28 @@
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*
*/
package openid
import "github.com/pkg/errors"
var (
ErrInvalidSession = errors.New("Session type mismatch")
)

Some files were not shown because too many files have changed in this diff Show More