seba-365 - implemented dep
Change-Id: Ia6226d50e7615935a0c8876809a687427ff88c22
diff --git a/vendor/github.com/xdg/scram/.gitignore b/vendor/github.com/xdg/scram/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/vendor/github.com/xdg/scram/.gitignore
diff --git a/vendor/github.com/xdg/scram/.travis.yml b/vendor/github.com/xdg/scram/.travis.yml
new file mode 100644
index 0000000..f391327
--- /dev/null
+++ b/vendor/github.com/xdg/scram/.travis.yml
@@ -0,0 +1,11 @@
+language: go
+sudo: false
+go:
+ - "1.7"
+ - "1.8"
+ - "1.9"
+ - "1.10"
+ - master
+matrix:
+ allow_failures:
+ - go: master
diff --git a/vendor/github.com/xdg/scram/LICENSE b/vendor/github.com/xdg/scram/LICENSE
new file mode 100644
index 0000000..67db858
--- /dev/null
+++ b/vendor/github.com/xdg/scram/LICENSE
@@ -0,0 +1,175 @@
+
+ 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.
diff --git a/vendor/github.com/xdg/scram/README.md b/vendor/github.com/xdg/scram/README.md
new file mode 100644
index 0000000..6782d94
--- /dev/null
+++ b/vendor/github.com/xdg/scram/README.md
@@ -0,0 +1,71 @@
+[![GoDoc](https://godoc.org/github.com/xdg/scram?status.svg)](https://godoc.org/github.com/xdg/scram)
+[![Build Status](https://travis-ci.org/xdg/scram.svg?branch=master)](https://travis-ci.org/xdg/scram)
+
+# scram – Go implementation of RFC-5802
+
+## Description
+
+Package scram provides client and server implementations of the Salted
+Challenge Response Authentication Mechanism (SCRAM) described in
+[RFC-5802](https://tools.ietf.org/html/rfc5802) and
+[RFC-7677](https://tools.ietf.org/html/rfc7677).
+
+It includes both client and server side support.
+
+Channel binding and extensions are not (yet) supported.
+
+## Examples
+
+### Client side
+
+ package main
+
+ import "github.com/xdg/scram"
+
+ func main() {
+ // Get Client with username, password and (optional) authorization ID.
+ clientSHA1, err := scram.SHA1.NewClient("mulder", "trustno1", "")
+ if err != nil {
+ panic(err)
+ }
+
+ // Prepare the authentication conversation. Use the empty string as the
+ // initial server message argument to start the conversation.
+ conv := clientSHA1.NewConversation()
+ var serverMsg string
+
+ // Get the first message, send it and read the response.
+ firstMsg, err := conv.Step(serverMsg)
+ if err != nil {
+ panic(err)
+ }
+ serverMsg = sendClientMsg(firstMsg)
+
+ // Get the second message, send it, and read the response.
+ secondMsg, err := conv.Step(serverMsg)
+ if err != nil {
+ panic(err)
+ }
+ serverMsg = sendClientMsg(secondMsg)
+
+ // Validate the server's final message. We have no further message to
+ // send so ignore that return value.
+ _, err = conv.Step(serverMsg)
+ if err != nil {
+ panic(err)
+ }
+
+ return
+ }
+
+ func sendClientMsg(s string) string {
+ // A real implementation would send this to a server and read a reply.
+ return ""
+ }
+
+## Copyright and License
+
+Copyright 2018 by David A. Golden. All rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License"). You may
+obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
diff --git a/vendor/github.com/xdg/scram/client.go b/vendor/github.com/xdg/scram/client.go
new file mode 100644
index 0000000..ca0c4c7
--- /dev/null
+++ b/vendor/github.com/xdg/scram/client.go
@@ -0,0 +1,130 @@
+// Copyright 2018 by David A. Golden. All rights reserved.
+//
+// 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
+
+package scram
+
+import (
+ "sync"
+
+ "golang.org/x/crypto/pbkdf2"
+)
+
+// Client implements the client side of SCRAM authentication. It holds
+// configuration values needed to initialize new client-side conversations for
+// a specific username, password and authorization ID tuple. Client caches
+// the computationally-expensive parts of a SCRAM conversation as described in
+// RFC-5802. If repeated authentication conversations may be required for a
+// user (e.g. disconnect/reconnect), the user's Client should be preserved.
+//
+// For security reasons, Clients have a default minimum PBKDF2 iteration count
+// of 4096. If a server requests a smaller iteration count, an authentication
+// conversation will error.
+//
+// A Client can also be used by a server application to construct the hashed
+// authentication values to be stored for a new user. See StoredCredentials()
+// for more.
+type Client struct {
+ sync.RWMutex
+ username string
+ password string
+ authzID string
+ minIters int
+ nonceGen NonceGeneratorFcn
+ hashGen HashGeneratorFcn
+ cache map[KeyFactors]derivedKeys
+}
+
+func newClient(username, password, authzID string, fcn HashGeneratorFcn) *Client {
+ return &Client{
+ username: username,
+ password: password,
+ authzID: authzID,
+ minIters: 4096,
+ nonceGen: defaultNonceGenerator,
+ hashGen: fcn,
+ cache: make(map[KeyFactors]derivedKeys),
+ }
+}
+
+// WithMinIterations changes minimum required PBKDF2 iteration count.
+func (c *Client) WithMinIterations(n int) *Client {
+ c.Lock()
+ defer c.Unlock()
+ c.minIters = n
+ return c
+}
+
+// WithNonceGenerator replaces the default nonce generator (base64 encoding of
+// 24 bytes from crypto/rand) with a custom generator. This is provided for
+// testing or for users with custom nonce requirements.
+func (c *Client) WithNonceGenerator(ng NonceGeneratorFcn) *Client {
+ c.Lock()
+ defer c.Unlock()
+ c.nonceGen = ng
+ return c
+}
+
+// NewConversation constructs a client-side authentication conversation.
+// Conversations cannot be reused, so this must be called for each new
+// authentication attempt.
+func (c *Client) NewConversation() *ClientConversation {
+ c.RLock()
+ defer c.RUnlock()
+ return &ClientConversation{
+ client: c,
+ nonceGen: c.nonceGen,
+ hashGen: c.hashGen,
+ minIters: c.minIters,
+ }
+}
+
+func (c *Client) getDerivedKeys(kf KeyFactors) derivedKeys {
+ dk, ok := c.getCache(kf)
+ if !ok {
+ dk = c.computeKeys(kf)
+ c.setCache(kf, dk)
+ }
+ return dk
+}
+
+// GetStoredCredentials takes a salt and iteration count structure and
+// provides the values that must be stored by a server to authentication a
+// user. These values are what the Server credential lookup function must
+// return for a given username.
+func (c *Client) GetStoredCredentials(kf KeyFactors) StoredCredentials {
+ dk := c.getDerivedKeys(kf)
+ return StoredCredentials{
+ KeyFactors: kf,
+ StoredKey: dk.StoredKey,
+ ServerKey: dk.ServerKey,
+ }
+}
+
+func (c *Client) computeKeys(kf KeyFactors) derivedKeys {
+ h := c.hashGen()
+ saltedPassword := pbkdf2.Key([]byte(c.password), []byte(kf.Salt), kf.Iters, h.Size(), c.hashGen)
+ clientKey := computeHMAC(c.hashGen, saltedPassword, []byte("Client Key"))
+
+ return derivedKeys{
+ ClientKey: clientKey,
+ StoredKey: computeHash(c.hashGen, clientKey),
+ ServerKey: computeHMAC(c.hashGen, saltedPassword, []byte("Server Key")),
+ }
+}
+
+func (c *Client) getCache(kf KeyFactors) (derivedKeys, bool) {
+ c.RLock()
+ defer c.RUnlock()
+ dk, ok := c.cache[kf]
+ return dk, ok
+}
+
+func (c *Client) setCache(kf KeyFactors, dk derivedKeys) {
+ c.Lock()
+ defer c.Unlock()
+ c.cache[kf] = dk
+ return
+}
diff --git a/vendor/github.com/xdg/scram/client_conv.go b/vendor/github.com/xdg/scram/client_conv.go
new file mode 100644
index 0000000..8340568
--- /dev/null
+++ b/vendor/github.com/xdg/scram/client_conv.go
@@ -0,0 +1,149 @@
+// Copyright 2018 by David A. Golden. All rights reserved.
+//
+// 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
+
+package scram
+
+import (
+ "crypto/hmac"
+ "encoding/base64"
+ "errors"
+ "fmt"
+ "strings"
+)
+
+type clientState int
+
+const (
+ clientStarting clientState = iota
+ clientFirst
+ clientFinal
+ clientDone
+)
+
+// ClientConversation implements the client-side of an authentication
+// conversation with a server. A new conversation must be created for
+// each authentication attempt.
+type ClientConversation struct {
+ client *Client
+ nonceGen NonceGeneratorFcn
+ hashGen HashGeneratorFcn
+ minIters int
+ state clientState
+ valid bool
+ gs2 string
+ nonce string
+ c1b string
+ serveSig []byte
+}
+
+// Step takes a string provided from a server (or just an empty string for the
+// very first conversation step) and attempts to move the authentication
+// conversation forward. It returns a string to be sent to the server or an
+// error if the server message is invalid. Calling Step after a conversation
+// completes is also an error.
+func (cc *ClientConversation) Step(challenge string) (response string, err error) {
+ switch cc.state {
+ case clientStarting:
+ cc.state = clientFirst
+ response, err = cc.firstMsg()
+ case clientFirst:
+ cc.state = clientFinal
+ response, err = cc.finalMsg(challenge)
+ case clientFinal:
+ cc.state = clientDone
+ response, err = cc.validateServer(challenge)
+ default:
+ response, err = "", errors.New("Conversation already completed")
+ }
+ return
+}
+
+// Done returns true if the conversation is completed or has errored.
+func (cc *ClientConversation) Done() bool {
+ return cc.state == clientDone
+}
+
+// Valid returns true if the conversation successfully authenticated with the
+// server, including counter-validation that the server actually has the
+// user's stored credentials.
+func (cc *ClientConversation) Valid() bool {
+ return cc.valid
+}
+
+func (cc *ClientConversation) firstMsg() (string, error) {
+ // Values are cached for use in final message parameters
+ cc.gs2 = cc.gs2Header()
+ cc.nonce = cc.client.nonceGen()
+ cc.c1b = fmt.Sprintf("n=%s,r=%s", encodeName(cc.client.username), cc.nonce)
+
+ return cc.gs2 + cc.c1b, nil
+}
+
+func (cc *ClientConversation) finalMsg(s1 string) (string, error) {
+ msg, err := parseServerFirst(s1)
+ if err != nil {
+ return "", err
+ }
+
+ // Check nonce prefix and update
+ if !strings.HasPrefix(msg.nonce, cc.nonce) {
+ return "", errors.New("server nonce did not extend client nonce")
+ }
+ cc.nonce = msg.nonce
+
+ // Check iteration count vs minimum
+ if msg.iters < cc.minIters {
+ return "", fmt.Errorf("server requested too few iterations (%d)", msg.iters)
+ }
+
+ // Create client-final-message-without-proof
+ c2wop := fmt.Sprintf(
+ "c=%s,r=%s",
+ base64.StdEncoding.EncodeToString([]byte(cc.gs2)),
+ cc.nonce,
+ )
+
+ // Create auth message
+ authMsg := cc.c1b + "," + s1 + "," + c2wop
+
+ // Get derived keys from client cache
+ dk := cc.client.getDerivedKeys(KeyFactors{Salt: string(msg.salt), Iters: msg.iters})
+
+ // Create proof as clientkey XOR clientsignature
+ clientSignature := computeHMAC(cc.hashGen, dk.StoredKey, []byte(authMsg))
+ clientProof := xorBytes(dk.ClientKey, clientSignature)
+ proof := base64.StdEncoding.EncodeToString(clientProof)
+
+ // Cache ServerSignature for later validation
+ cc.serveSig = computeHMAC(cc.hashGen, dk.ServerKey, []byte(authMsg))
+
+ return fmt.Sprintf("%s,p=%s", c2wop, proof), nil
+}
+
+func (cc *ClientConversation) validateServer(s2 string) (string, error) {
+ msg, err := parseServerFinal(s2)
+ if err != nil {
+ return "", err
+ }
+
+ if len(msg.err) > 0 {
+ return "", fmt.Errorf("server error: %s", msg.err)
+ }
+
+ if !hmac.Equal(msg.verifier, cc.serveSig) {
+ return "", errors.New("server validation failed")
+ }
+
+ cc.valid = true
+ return "", nil
+}
+
+func (cc *ClientConversation) gs2Header() string {
+ if cc.client.authzID == "" {
+ return "n,,"
+ }
+ return fmt.Sprintf("n,%s,", encodeName(cc.client.authzID))
+}
diff --git a/vendor/github.com/xdg/scram/common.go b/vendor/github.com/xdg/scram/common.go
new file mode 100644
index 0000000..cb705cb
--- /dev/null
+++ b/vendor/github.com/xdg/scram/common.go
@@ -0,0 +1,97 @@
+// Copyright 2018 by David A. Golden. All rights reserved.
+//
+// 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
+
+package scram
+
+import (
+ "crypto/hmac"
+ "crypto/rand"
+ "encoding/base64"
+ "strings"
+)
+
+// NonceGeneratorFcn defines a function that returns a string of high-quality
+// random printable ASCII characters EXCLUDING the comma (',') character. The
+// default nonce generator provides Base64 encoding of 24 bytes from
+// crypto/rand.
+type NonceGeneratorFcn func() string
+
+// derivedKeys collects the three cryptographically derived values
+// into one struct for caching.
+type derivedKeys struct {
+ ClientKey []byte
+ StoredKey []byte
+ ServerKey []byte
+}
+
+// KeyFactors represent the two server-provided factors needed to compute
+// client credentials for authentication. Salt is decoded bytes (i.e. not
+// base64), but in string form so that KeyFactors can be used as a map key for
+// cached credentials.
+type KeyFactors struct {
+ Salt string
+ Iters int
+}
+
+// StoredCredentials are the values that a server must store for a given
+// username to allow authentication. They include the salt and iteration
+// count, plus the derived values to authenticate a client and for the server
+// to authenticate itself back to the client.
+//
+// NOTE: these are specific to a given hash function. To allow a user to
+// authenticate with either SCRAM-SHA-1 or SCRAM-SHA-256, two sets of
+// StoredCredentials must be created and stored, one for each hash function.
+type StoredCredentials struct {
+ KeyFactors
+ StoredKey []byte
+ ServerKey []byte
+}
+
+// CredentialLookup is a callback to provide StoredCredentials for a given
+// username. This is used to configure Server objects.
+//
+// NOTE: these are specific to a given hash function. The callback provided
+// to a Server with a given hash function must provide the corresponding
+// StoredCredentials.
+type CredentialLookup func(string) (StoredCredentials, error)
+
+func defaultNonceGenerator() string {
+ raw := make([]byte, 24)
+ nonce := make([]byte, base64.StdEncoding.EncodedLen(len(raw)))
+ rand.Read(raw)
+ base64.StdEncoding.Encode(nonce, raw)
+ return string(nonce)
+}
+
+func encodeName(s string) string {
+ return strings.Replace(strings.Replace(s, "=", "=3D", -1), ",", "=2C", -1)
+}
+
+func decodeName(s string) (string, error) {
+ // TODO Check for = not followed by 2C or 3D
+ return strings.Replace(strings.Replace(s, "=2C", ",", -1), "=3D", "=", -1), nil
+}
+
+func computeHash(hg HashGeneratorFcn, b []byte) []byte {
+ h := hg()
+ h.Write(b)
+ return h.Sum(nil)
+}
+
+func computeHMAC(hg HashGeneratorFcn, key, data []byte) []byte {
+ mac := hmac.New(hg, key)
+ mac.Write(data)
+ return mac.Sum(nil)
+}
+
+func xorBytes(a, b []byte) []byte {
+ // TODO check a & b are same length, or just xor to smallest
+ xor := make([]byte, len(a))
+ for i := range a {
+ xor[i] = a[i] ^ b[i]
+ }
+ return xor
+}
diff --git a/vendor/github.com/xdg/scram/doc.go b/vendor/github.com/xdg/scram/doc.go
new file mode 100644
index 0000000..d43bee6
--- /dev/null
+++ b/vendor/github.com/xdg/scram/doc.go
@@ -0,0 +1,24 @@
+// Copyright 2018 by David A. Golden. All rights reserved.
+//
+// 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
+
+// Package scram provides client and server implementations of the Salted
+// Challenge Response Authentication Mechanism (SCRAM) described in RFC-5802
+// and RFC-7677.
+//
+// Usage
+//
+// The scram package provides two variables, `SHA1` and `SHA256`, that are
+// used to construct Client or Server objects.
+//
+// clientSHA1, err := scram.SHA1.NewClient(username, password, authID)
+// clientSHA256, err := scram.SHA256.NewClient(username, password, authID)
+//
+// serverSHA1, err := scram.SHA1.NewServer(credentialLookupFcn)
+// serverSHA256, err := scram.SHA256.NewServer(credentialLookupFcn)
+//
+// These objects are used to construct ClientConversation or
+// ServerConversation objects that are used to carry out authentication.
+package scram
diff --git a/vendor/github.com/xdg/scram/parse.go b/vendor/github.com/xdg/scram/parse.go
new file mode 100644
index 0000000..722f604
--- /dev/null
+++ b/vendor/github.com/xdg/scram/parse.go
@@ -0,0 +1,205 @@
+// Copyright 2018 by David A. Golden. All rights reserved.
+//
+// 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
+
+package scram
+
+import (
+ "encoding/base64"
+ "errors"
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+type c1Msg struct {
+ gs2Header string
+ authzID string
+ username string
+ nonce string
+ c1b string
+}
+
+type c2Msg struct {
+ cbind []byte
+ nonce string
+ proof []byte
+ c2wop string
+}
+
+type s1Msg struct {
+ nonce string
+ salt []byte
+ iters int
+}
+
+type s2Msg struct {
+ verifier []byte
+ err string
+}
+
+func parseField(s, k string) (string, error) {
+ t := strings.TrimPrefix(s, k+"=")
+ if t == s {
+ return "", fmt.Errorf("error parsing '%s' for field '%s'", s, k)
+ }
+ return t, nil
+}
+
+func parseGS2Flag(s string) (string, error) {
+ if s[0] == 'p' {
+ return "", fmt.Errorf("channel binding requested but not supported")
+ }
+
+ if s == "n" || s == "y" {
+ return s, nil
+ }
+
+ return "", fmt.Errorf("error parsing '%s' for gs2 flag", s)
+}
+
+func parseFieldBase64(s, k string) ([]byte, error) {
+ raw, err := parseField(s, k)
+ if err != nil {
+ return nil, err
+ }
+
+ dec, err := base64.StdEncoding.DecodeString(raw)
+ if err != nil {
+ return nil, err
+ }
+
+ return dec, nil
+}
+
+func parseFieldInt(s, k string) (int, error) {
+ raw, err := parseField(s, k)
+ if err != nil {
+ return 0, err
+ }
+
+ num, err := strconv.Atoi(raw)
+ if err != nil {
+ return 0, fmt.Errorf("error parsing field '%s': %v", k, err)
+ }
+
+ return num, nil
+}
+
+func parseClientFirst(c1 string) (msg c1Msg, err error) {
+
+ fields := strings.Split(c1, ",")
+ if len(fields) < 4 {
+ err = errors.New("not enough fields in first server message")
+ return
+ }
+
+ gs2flag, err := parseGS2Flag(fields[0])
+ if err != nil {
+ return
+ }
+
+ // 'a' field is optional
+ if len(fields[1]) > 0 {
+ msg.authzID, err = parseField(fields[1], "a")
+ if err != nil {
+ return
+ }
+ }
+
+ // Recombine and save the gs2 header
+ msg.gs2Header = gs2flag + "," + msg.authzID + ","
+
+ // Check for unsupported extensions field "m".
+ if strings.HasPrefix(fields[2], "m=") {
+ err = errors.New("SCRAM message extensions are not supported")
+ return
+ }
+
+ msg.username, err = parseField(fields[2], "n")
+ if err != nil {
+ return
+ }
+
+ msg.nonce, err = parseField(fields[3], "r")
+ if err != nil {
+ return
+ }
+
+ msg.c1b = strings.Join(fields[2:], ",")
+
+ return
+}
+
+func parseClientFinal(c2 string) (msg c2Msg, err error) {
+ fields := strings.Split(c2, ",")
+ if len(fields) < 3 {
+ err = errors.New("not enough fields in first server message")
+ return
+ }
+
+ msg.cbind, err = parseFieldBase64(fields[0], "c")
+ if err != nil {
+ return
+ }
+
+ msg.nonce, err = parseField(fields[1], "r")
+ if err != nil {
+ return
+ }
+
+ // Extension fields may come between nonce and proof, so we
+ // grab the *last* fields as proof.
+ msg.proof, err = parseFieldBase64(fields[len(fields)-1], "p")
+ if err != nil {
+ return
+ }
+
+ msg.c2wop = c2[:strings.LastIndex(c2, ",")]
+
+ return
+}
+
+func parseServerFirst(s1 string) (msg s1Msg, err error) {
+
+ // Check for unsupported extensions field "m".
+ if strings.HasPrefix(s1, "m=") {
+ err = errors.New("SCRAM message extensions are not supported")
+ return
+ }
+
+ fields := strings.Split(s1, ",")
+ if len(fields) < 3 {
+ err = errors.New("not enough fields in first server message")
+ return
+ }
+
+ msg.nonce, err = parseField(fields[0], "r")
+ if err != nil {
+ return
+ }
+
+ msg.salt, err = parseFieldBase64(fields[1], "s")
+ if err != nil {
+ return
+ }
+
+ msg.iters, err = parseFieldInt(fields[2], "i")
+
+ return
+}
+
+func parseServerFinal(s2 string) (msg s2Msg, err error) {
+ fields := strings.Split(s2, ",")
+
+ msg.verifier, err = parseFieldBase64(fields[0], "v")
+ if err == nil {
+ return
+ }
+
+ msg.err, err = parseField(fields[0], "e")
+
+ return
+}
diff --git a/vendor/github.com/xdg/scram/scram.go b/vendor/github.com/xdg/scram/scram.go
new file mode 100644
index 0000000..9e9836a
--- /dev/null
+++ b/vendor/github.com/xdg/scram/scram.go
@@ -0,0 +1,66 @@
+// Copyright 2018 by David A. Golden. All rights reserved.
+//
+// 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
+
+package scram
+
+import (
+ "crypto/sha1"
+ "crypto/sha256"
+ "fmt"
+ "hash"
+
+ "github.com/xdg/stringprep"
+)
+
+// HashGeneratorFcn abstracts a factory function that returns a hash.Hash
+// value to be used for SCRAM operations. Generally, one would use the
+// provided package variables, `scram.SHA1` and `scram.SHA256`, for the most
+// common forms of SCRAM.
+type HashGeneratorFcn func() hash.Hash
+
+// SHA1 is a function that returns a crypto/sha1 hasher and should be used to
+// create Client objects configured for SHA-1 hashing.
+var SHA1 HashGeneratorFcn = func() hash.Hash { return sha1.New() }
+
+// SHA256 is a function that returns a crypto/sha256 hasher and should be used
+// to create Client objects configured for SHA-256 hashing.
+var SHA256 HashGeneratorFcn = func() hash.Hash { return sha256.New() }
+
+// NewClient constructs a SCRAM client component based on a given hash.Hash
+// factory receiver. This constructor will normalize the username, password
+// and authzID via the SASLprep algorithm, as recommended by RFC-5802. If
+// SASLprep fails, the method returns an error.
+func (f HashGeneratorFcn) NewClient(username, password, authzID string) (*Client, error) {
+ var userprep, passprep, authprep string
+ var err error
+
+ if userprep, err = stringprep.SASLprep.Prepare(username); err != nil {
+ return nil, fmt.Errorf("Error SASLprepping username '%s': %v", username, err)
+ }
+ if passprep, err = stringprep.SASLprep.Prepare(password); err != nil {
+ return nil, fmt.Errorf("Error SASLprepping password '%s': %v", password, err)
+ }
+ if authprep, err = stringprep.SASLprep.Prepare(authzID); err != nil {
+ return nil, fmt.Errorf("Error SASLprepping authzID '%s': %v", authzID, err)
+ }
+
+ return newClient(userprep, passprep, authprep, f), nil
+}
+
+// NewClientUnprepped acts like NewClient, except none of the arguments will
+// be normalized via SASLprep. This is not generally recommended, but is
+// provided for users that may have custom normalization needs.
+func (f HashGeneratorFcn) NewClientUnprepped(username, password, authzID string) (*Client, error) {
+ return newClient(username, password, authzID, f), nil
+}
+
+// NewServer constructs a SCRAM server component based on a given hash.Hash
+// factory receiver. To be maximally generic, it uses dependency injection to
+// handle credential lookup, which is the process of turning a username string
+// into a struct with stored credentials for authentication.
+func (f HashGeneratorFcn) NewServer(cl CredentialLookup) (*Server, error) {
+ return newServer(cl, f)
+}
diff --git a/vendor/github.com/xdg/scram/server.go b/vendor/github.com/xdg/scram/server.go
new file mode 100644
index 0000000..b119b36
--- /dev/null
+++ b/vendor/github.com/xdg/scram/server.go
@@ -0,0 +1,50 @@
+// Copyright 2018 by David A. Golden. All rights reserved.
+//
+// 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
+
+package scram
+
+import "sync"
+
+// Server implements the server side of SCRAM authentication. It holds
+// configuration values needed to initialize new server-side conversations.
+// Generally, this can be persistent within an application.
+type Server struct {
+ sync.RWMutex
+ credentialCB CredentialLookup
+ nonceGen NonceGeneratorFcn
+ hashGen HashGeneratorFcn
+}
+
+func newServer(cl CredentialLookup, fcn HashGeneratorFcn) (*Server, error) {
+ return &Server{
+ credentialCB: cl,
+ nonceGen: defaultNonceGenerator,
+ hashGen: fcn,
+ }, nil
+}
+
+// WithNonceGenerator replaces the default nonce generator (base64 encoding of
+// 24 bytes from crypto/rand) with a custom generator. This is provided for
+// testing or for users with custom nonce requirements.
+func (s *Server) WithNonceGenerator(ng NonceGeneratorFcn) *Server {
+ s.Lock()
+ defer s.Unlock()
+ s.nonceGen = ng
+ return s
+}
+
+// NewConversation constructs a server-side authentication conversation.
+// Conversations cannot be reused, so this must be called for each new
+// authentication attempt.
+func (s *Server) NewConversation() *ServerConversation {
+ s.RLock()
+ defer s.RUnlock()
+ return &ServerConversation{
+ nonceGen: s.nonceGen,
+ hashGen: s.hashGen,
+ credentialCB: s.credentialCB,
+ }
+}
diff --git a/vendor/github.com/xdg/scram/server_conv.go b/vendor/github.com/xdg/scram/server_conv.go
new file mode 100644
index 0000000..9c8838c
--- /dev/null
+++ b/vendor/github.com/xdg/scram/server_conv.go
@@ -0,0 +1,151 @@
+// Copyright 2018 by David A. Golden. All rights reserved.
+//
+// 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
+
+package scram
+
+import (
+ "crypto/hmac"
+ "encoding/base64"
+ "errors"
+ "fmt"
+)
+
+type serverState int
+
+const (
+ serverFirst serverState = iota
+ serverFinal
+ serverDone
+)
+
+// ServerConversation implements the server-side of an authentication
+// conversation with a client. A new conversation must be created for
+// each authentication attempt.
+type ServerConversation struct {
+ nonceGen NonceGeneratorFcn
+ hashGen HashGeneratorFcn
+ credentialCB CredentialLookup
+ state serverState
+ credential StoredCredentials
+ valid bool
+ gs2Header string
+ username string
+ authzID string
+ nonce string
+ c1b string
+ s1 string
+}
+
+// Step takes a string provided from a client and attempts to move the
+// authentication conversation forward. It returns a string to be sent to the
+// client or an error if the client message is invalid. Calling Step after a
+// conversation completes is also an error.
+func (sc *ServerConversation) Step(challenge string) (response string, err error) {
+ switch sc.state {
+ case serverFirst:
+ sc.state = serverFinal
+ response, err = sc.firstMsg(challenge)
+ case serverFinal:
+ sc.state = serverDone
+ response, err = sc.finalMsg(challenge)
+ default:
+ response, err = "", errors.New("Conversation already completed")
+ }
+ return
+}
+
+// Done returns true if the conversation is completed or has errored.
+func (sc *ServerConversation) Done() bool {
+ return sc.state == serverDone
+}
+
+// Valid returns true if the conversation successfully authenticated the
+// client.
+func (sc *ServerConversation) Valid() bool {
+ return sc.valid
+}
+
+// Username returns the client-provided username. This is valid to call
+// if the first conversation Step() is successful.
+func (sc *ServerConversation) Username() string {
+ return sc.username
+}
+
+// AuthzID returns the (optional) client-provided authorization identity, if
+// any. If one was not provided, it returns the empty string. This is valid
+// to call if the first conversation Step() is successful.
+func (sc *ServerConversation) AuthzID() string {
+ return sc.authzID
+}
+
+func (sc *ServerConversation) firstMsg(c1 string) (string, error) {
+ msg, err := parseClientFirst(c1)
+ if err != nil {
+ sc.state = serverDone
+ return "", err
+ }
+
+ sc.gs2Header = msg.gs2Header
+ sc.username = msg.username
+ sc.authzID = msg.authzID
+
+ sc.credential, err = sc.credentialCB(msg.username)
+ if err != nil {
+ sc.state = serverDone
+ return "e=unknown-user", err
+ }
+
+ sc.nonce = msg.nonce + sc.nonceGen()
+ sc.c1b = msg.c1b
+ sc.s1 = fmt.Sprintf("r=%s,s=%s,i=%d",
+ sc.nonce,
+ base64.StdEncoding.EncodeToString([]byte(sc.credential.Salt)),
+ sc.credential.Iters,
+ )
+
+ return sc.s1, nil
+}
+
+// For errors, returns server error message as well as non-nil error. Callers
+// can choose whether to send server error or not.
+func (sc *ServerConversation) finalMsg(c2 string) (string, error) {
+ msg, err := parseClientFinal(c2)
+ if err != nil {
+ return "", err
+ }
+
+ // Check channel binding matches what we expect; in this case, we expect
+ // just the gs2 header we received as we don't support channel binding
+ // with a data payload. If we add binding, we need to independently
+ // compute the header to match here.
+ if string(msg.cbind) != sc.gs2Header {
+ return "e=channel-bindings-dont-match", fmt.Errorf("channel binding received '%s' doesn't match expected '%s'", msg.cbind, sc.gs2Header)
+ }
+
+ // Check nonce received matches what we sent
+ if msg.nonce != sc.nonce {
+ return "e=other-error", errors.New("nonce received did not match nonce sent")
+ }
+
+ // Create auth message
+ authMsg := sc.c1b + "," + sc.s1 + "," + msg.c2wop
+
+ // Retrieve ClientKey from proof and verify it
+ clientSignature := computeHMAC(sc.hashGen, sc.credential.StoredKey, []byte(authMsg))
+ clientKey := xorBytes([]byte(msg.proof), clientSignature)
+ storedKey := computeHash(sc.hashGen, clientKey)
+
+ // Compare with constant-time function
+ if !hmac.Equal(storedKey, sc.credential.StoredKey) {
+ return "e=invalid-proof", errors.New("challenge proof invalid")
+ }
+
+ sc.valid = true
+
+ // Compute and return server verifier
+ serverSignature := computeHMAC(sc.hashGen, sc.credential.ServerKey, []byte(authMsg))
+ return "v=" + base64.StdEncoding.EncodeToString(serverSignature), nil
+}