Skip to content
This repository has been archived by the owner on Feb 16, 2023. It is now read-only.

Commit

Permalink
Merge pull request #123 from secrethub/release/v0.21.0
Browse files Browse the repository at this point in the history
Release v0.21.0
  • Loading branch information
jpcoenen authored Sep 3, 2019
2 parents 1ecfe62 + beb98f3 commit 30f776a
Show file tree
Hide file tree
Showing 100 changed files with 5,617 additions and 3,006 deletions.
12 changes: 0 additions & 12 deletions .gitlab-ci.yml

This file was deleted.

7 changes: 0 additions & 7 deletions .travis.yml

This file was deleted.

4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</h1>

[![GoDoc](http://img.shields.io/badge/godoc-reference-blue.svg)][godoc]
[![Travis CI](https://travis-ci.org/secrethub/secrethub-go.svg?branch=master)][travis-ci]
[![CircleCI](https://circleci.com/gh/secrethub/secrethub-go.svg?style=shield)][circle-ci]
[![GolangCI](https://golangci.com/badges/github.com/secrethub/secrethub-go.svg)][golang-ci]
[![Go Report Card](https://goreportcard.com/badge/github.com/secrethub/secrethub-go)][goreportcard]
[![Version]( https://img.shields.io/github/release/secrethub/secrethub-go.svg)][latest-version]
Expand Down Expand Up @@ -121,5 +121,5 @@ Come chat with us on [Discord][discord] or email us at [support@secrethub.io](ma
[godoc]: http://godoc.org/github.com/secrethub/secrethub-go
[golang-ci]: https://golangci.com/r/github.com/secrethub/secrethub-go
[goreportcard]: https://goreportcard.com/report/github.com/secrethub/secrethub-go
[travis-ci]: https://travis-ci.org/secrethub/secrethub-go
[circle-ci]: https://circleci.com/gh/secrethub/secrethub-go
[discord]: https://discord.gg/EQcE87s
8 changes: 7 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,19 @@ module github.com/secrethub/secrethub-go
require (
bitbucket.org/zombiezen/cardcpx v0.0.0-20150417151802-902f68ff43ef
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf
github.com/aws/aws-sdk-go v1.19.38
github.com/docker/docker v1.13.1
github.com/docker/go-units v0.3.3
github.com/go-chi/chi v4.0.1+incompatible
github.com/google/go-querystring v1.0.0
github.com/kr/pretty v0.1.0 // indirect
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348
github.com/mattn/go-shellwords v1.0.6 // indirect
github.com/mitchellh/go-homedir v1.1.0
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
github.com/satori/go.uuid v1.2.0
golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b
github.com/stretchr/testify v1.3.0 // indirect
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
golang.org/x/net v0.0.0-20190522155817-f3200d17e092 // indirect
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
)
26 changes: 24 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,46 @@ bitbucket.org/zombiezen/cardcpx v0.0.0-20150417151802-902f68ff43ef h1:Y5Zf3CYdrd
bitbucket.org/zombiezen/cardcpx v0.0.0-20150417151802-902f68ff43ef/go.mod h1:ZJR5FpaQx7Bt2bzIV3gBaCInI1+kG949WhNYYlRr8eA=
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.19.38 h1:WKjobgPO4Ua1ww2NJJl2/zQNreUZxvqmEzwMlRjjm9g=
github.com/aws/aws-sdk-go v1.19.38/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/docker v1.13.1 h1:IkZjBSIc8hBjLpqeAbeE5mca5mNgeatLHBy3GO78BWo=
github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk=
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/go-chi/chi v4.0.1+incompatible h1:RSRC5qmFPtO90t7pTL0DBMNpZFsb/sHF3RXVlDgFisA=
github.com/go-chi/chi v4.0.1+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
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/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3vkb4ax0b5D2DHbNAUsen0Gx5wZoq3lV4=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
github.com/mattn/go-shellwords v1.0.6 h1:9Jok5pILi5S1MnDirGVTufYGtksUs/V2BWUP3ZkeUUI=
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
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/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b h1:+/WWzjwW6gidDJnMKWLKLX1gxn7irUTF1fLpQovfQ5M=
golang.org/x/crypto v0.0.0-20190225124518-7f87c0fbb88b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
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/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
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=
18 changes: 10 additions & 8 deletions internals/api/account_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,36 @@ package api

import (
"net/http"

"github.com/secrethub/secrethub-go/internals/crypto"
)

// Errors
var (
ErrAccountNotKeyed = errAPI.Code("account_not_keyed").StatusError("User has not yet keyed their account", http.StatusBadRequest)
ErrAccountKeyNotFound = errAPI.Code("account_key_not_found").StatusError("User has not yet keyed their account", http.StatusNotFound)
ErrIllegalKeyVersion = errHub.Code("illegal_key_version").StatusError("key_version should be either v1 or v2", http.StatusBadRequest)
)

// EncryptedAccountKey represents an account key encrypted with a credential.
type EncryptedAccountKey struct {
Account *Account
PublicKey []byte
EncryptedPrivateKey crypto.CiphertextRSAAES
Credential *Credential
Account *Account `json:"account"`
PublicKey []byte `json:"public_key"`
EncryptedPrivateKey *EncryptedData `json:"encrypted_private_key"`
Credential *Credential `json:"credential"`
}

// CreateAccountKeyRequest contains the fields to add an account_key encrypted for a credential.
type CreateAccountKeyRequest struct {
EncryptedPrivateKey crypto.CiphertextRSAAES
PublicKey []byte
EncryptedPrivateKey *EncryptedData `json:"encrypted_private_key"`
PublicKey []byte `json:"public_key"`
}

// Validate checks whether the request is valid.
func (req CreateAccountKeyRequest) Validate() error {
if len(req.PublicKey) == 0 {
return ErrInvalidPublicKey
}
if err := req.EncryptedPrivateKey.Validate(); err != nil {
return err
}
return nil
}
247 changes: 247 additions & 0 deletions internals/api/auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
package api

import (
"encoding/json"
"net/http"
"time"

"github.com/secrethub/secrethub-go/internals/api/uuid"
)

// AuthMethod options
const (
AuthMethodAWSSTS = "aws-sts"
)

// SessionType options
const (
SessionTypeHMAC SessionType = "hmac"
)

// Errors
var (
ErrInvalidSessionType = errAPI.Code("invalid_session_type").StatusError("invalid session type provided for authentication request", http.StatusBadRequest)
ErrInvalidPayload = errAPI.Code("invalid_payload").StatusError("invalid payload provided for authentication request", http.StatusBadRequest)
ErrInvalidAuthMethod = errAPI.Code("invalid_auth_method").StatusError("invalid auth method", http.StatusBadRequest)
ErrMissingField = errAPI.Code("missing_field").StatusErrorPref("request is missing field %s", http.StatusBadRequest)
ErrSessionNotFound = errAPI.Code("session_not_found").StatusError("session could not be found, it might have expired", http.StatusForbidden)
ErrSessionExpired = errAPI.Code("session_expired").StatusError("session has expired", http.StatusForbidden)
ErrAuthFailed = errAPI.Code("auth_failed").StatusError("authentication failed", http.StatusForbidden)
ErrCouldNotGetEndpoint = errAPI.Code("aws_endpoint_not_found").StatusError("could not find an AWS endpoint for the provided region", http.StatusBadRequest)
ErrAWSException = errAPI.Code("aws_exception").StatusError("encountered an unexpected problem while verifying your identity on AWS. Please try again later.", http.StatusFailedDependency)
ErrNoServiceWithRole = errAPI.Code("no_service_with_role").StatusErrorPref("no service account found that is linked to the IAM role '%s'", http.StatusNotFound)
ErrNoAWSCredentials = errAPI.Code("missing_aws_credentials").StatusError("request was not signed with AWS credentials", http.StatusUnauthorized)
ErrInvalidAWSCredentials = errAPI.Code("invalid_aws_credentials").StatusError("credentials were not accepted by AWS", http.StatusUnauthorized)
)

// SessionType defines how a session can be used.
type SessionType string

// AuthRequest is a request to authenticate and request a session.
type AuthRequest struct {
Method string `json:"method"`
SessionType SessionType `json:"session_type"`
Payload interface{} `json:"payload"`
}

// AuthPayloadAWSSTS is the authentication payload used for authenticating with AWS STS.
type AuthPayloadAWSSTS struct {
Region string `json:"region"`
Request []byte `json:"request"`
}

// NewAuthRequestAWSSTS returns a new AuthRequest for authentication using AWS STS.
func NewAuthRequestAWSSTS(sessionType SessionType, region string, stsRequest []byte) AuthRequest {
return AuthRequest{
Method: AuthMethodAWSSTS,
SessionType: sessionType,
Payload: &AuthPayloadAWSSTS{
Region: region,
Request: stsRequest,
},
}
}

// UnmarshalJSON converts a JSON representation into a AuthRequest with the correct Payload.
func (r *AuthRequest) UnmarshalJSON(b []byte) error {
// Declare a private type to avoid recursion into this function.
type authRequest AuthRequest

var rawMessage json.RawMessage
dec := authRequest{
Payload: &rawMessage,
}

err := json.Unmarshal(b, &dec)
if err != nil {
return err
}

if dec.Method == "" {
return ErrMissingField("method")
}

switch dec.Method {
case AuthMethodAWSSTS:
dec.Payload = &AuthPayloadAWSSTS{}
default:
return ErrInvalidAuthMethod
}

if rawMessage != nil {
err = json.Unmarshal(rawMessage, dec.Payload)
if err != nil {
return err
}
}
*r = AuthRequest(dec)
return nil
}

// Validate whether an AuthRequest is a valid request.
func (r *AuthRequest) Validate() error {
if r.SessionType == "" {
return ErrMissingField("session_type")
}
if r.SessionType != SessionTypeHMAC {
return ErrInvalidSessionType
}
if r.Method == "" {
return ErrMissingField("method")
}
switch r.Method {
case AuthMethodAWSSTS:
authPayload, ok := r.Payload.(*AuthPayloadAWSSTS)
if !ok {
return ErrInvalidPayload
}
if err := authPayload.Validate(); err != nil {
return err
}
default:
return ErrInvalidAuthMethod
}
return nil
}

// Validate whether the AuthPayloadAWSSTS is valid.
func (pl AuthPayloadAWSSTS) Validate() error {
if pl.Region == "" {
return ErrMissingField("region")
}
if pl.Request == nil {
return ErrMissingField("request")
}
return nil
}

// NewSessionHMAC returns a HMAC type api.Session.
func NewSessionHMAC(sessionID uuid.UUID, expiration time.Time, secretKey string) *Session {
return &Session{
SessionID: sessionID,
ExpiresAt: expiration,
Type: SessionTypeHMAC,
Payload: &SessionPayloadHMAC{
SessionKey: secretKey,
},
}
}

// Session represents a session that can be used for authentication to the server.
type Session struct {
SessionID uuid.UUID `json:"session_id"`
ExpiresAt time.Time `json:"expires_at"`
Type SessionType `json:"type"`
Payload interface{} `json:"payload"`
}

// SessionPayloadHMAC is the payload of a HMAC typed session.
type SessionPayloadHMAC struct {
SessionKey string `json:"session_key"`
}

// Validate whether the SessionPayloadHMAC is valid.
func (pl *SessionPayloadHMAC) Validate() error {
if pl.SessionKey == "" {
return ErrMissingField("session_key")
}
return nil
}

// SessionHMAC is a session that uses the HMAC algorithm to verify the authentication.
type SessionHMAC struct {
SessionID uuid.UUID
Expires time.Time
Payload SessionPayloadHMAC
}

// UnmarshalJSON converts a JSON representation into a Session with the correct Payload.
func (s *Session) UnmarshalJSON(b []byte) error {
// Declare a private type to avoid recursion into this function.
type session Session

var rawMessage json.RawMessage
dec := session{
Payload: &rawMessage,
}

err := json.Unmarshal(b, &dec)
if err != nil {
return err
}

if dec.Type == "" {
return ErrMissingField("type")
}

switch dec.Type {
case SessionTypeHMAC:
dec.Payload = &SessionPayloadHMAC{}
default:
return ErrInvalidSessionType
}

if rawMessage != nil {
err = json.Unmarshal(rawMessage, dec.Payload)
if err != nil {
return err
}
}
*s = Session(dec)
return nil
}

type validator interface {
Validate() error
}

// Validate whether the Session is valid.
func (s *Session) Validate() error {
if s.ExpiresAt.IsZero() {
return ErrMissingField("expires_at")
}
if s.Type == "" {
return ErrMissingField("type")
}
if s.Type != SessionTypeHMAC {
return ErrInvalidSessionType
}
if s.Payload == nil {
return ErrMissingField("payload")
}
payload := s.Payload.(validator)
if err := payload.Validate(); err != nil {
return err
}
return nil
}

// HMAC returns the HMAC specific representation of this session.
func (s *Session) HMAC() *SessionHMAC {
payload := s.Payload.(*SessionPayloadHMAC)
return &SessionHMAC{
SessionID: s.SessionID,
Expires: s.ExpiresAt,
Payload: *payload,
}
}
Loading

0 comments on commit 30f776a

Please sign in to comment.