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

feat: #20 bootstrap data retrieve endpoint #46

Merged
merged 1 commit into from
Jul 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 60 additions & 14 deletions cmd/auth-rest/startcmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,19 @@ const (
googleClientSecretEnvKey = "AUTH_REST_GOOGLE_CLIENTSECRET" // nolint:gosec
)

// Bootstrap parameters.
const (
sdsURLFlagName = "sds-url"
sdsURLFlagUsage = "URL for the Secure Data Storage service." +
" Alternatively, this can be set with the following environment variable: " + sdsURLEnvKey
sdsURLEnvKey = "AUTH_REST_SDS_URL"

keyServerURLFlagName = "ks-url"
keyServerURLFlagUsage = "URL for the Key Server." +
" Alternatively, this can be set with the following environment variable: " + keyServerURLEnvKey
keyServerURLEnvKey = "AUTH_REST_KEYSERVER_URL"
)

const (
// api
healthCheckEndpoint = "/healthcheck"
Expand All @@ -122,13 +135,14 @@ const (
var logger = log.New("auth-rest")

type authRestParameters struct {
hostURL string
logLevel string
databaseType string
databaseURL string
databasePrefix string
tlsParams *tlsParams
oidcParams *oidcParams
hostURL string
logLevel string
databaseType string
databaseURL string
databasePrefix string
tlsParams *tlsParams
oidcParams *oidcParams
bootstrapParams *bootstrapParams
}

type tlsParams struct {
Expand All @@ -149,6 +163,11 @@ type oidcProviderParams struct {
clientSecret string
}

type bootstrapParams struct {
sdsURL string
keyServerURL string
}

type healthCheckResp struct {
Status string `json:"status"`
CurrentTime time.Time `json:"currentTime"`
Expand Down Expand Up @@ -233,14 +252,20 @@ func getAuthRestParameters(cmd *cobra.Command) (*authRestParameters, error) {
return nil, err
}

bootstrapParams, err := getBootstrapParams(cmd)
if err != nil {
return nil, err
}

return &authRestParameters{
hostURL: hostURL,
tlsParams: tlsParams,
logLevel: loggingLevel,
databaseType: databaseType,
databaseURL: databaseURL,
databasePrefix: databasePrefix,
oidcParams: oidcParams,
hostURL: hostURL,
tlsParams: tlsParams,
logLevel: loggingLevel,
databaseType: databaseType,
databaseURL: databaseURL,
databasePrefix: databasePrefix,
oidcParams: oidcParams,
bootstrapParams: bootstrapParams,
}, nil
}

Expand Down Expand Up @@ -293,6 +318,8 @@ func createFlags(startCmd *cobra.Command) {
startCmd.Flags().StringP(googleProviderFlagName, "", "", googleProviderFlagUsage)
startCmd.Flags().StringP(googleClientIDFlagName, "", "", googleClientIDFlagUsage)
startCmd.Flags().StringP(googleClientSecretFlagName, "", "", googleClientSecretFlagUsage)
startCmd.Flags().StringP(sdsURLFlagName, "", "", sdsURLFlagUsage)
startCmd.Flags().StringP(keyServerURLFlagName, "", "", keyServerURLFlagUsage)
}

func startAuthService(parameters *authRestParameters, srv server) error {
Expand Down Expand Up @@ -328,6 +355,10 @@ func startAuthService(parameters *authRestParameters, srv server) error {
OIDCProviderURL: parameters.oidcParams.google.providerURL,
OIDCClientID: parameters.oidcParams.google.clientID,
OIDCClientSecret: parameters.oidcParams.google.clientSecret,
BootstrapConfig: &operation.BootstrapConfig{
SDSURL: parameters.bootstrapParams.sdsURL,
KeyServerURL: parameters.bootstrapParams.keyServerURL,
},
})
if err != nil {
return err
Expand Down Expand Up @@ -391,6 +422,21 @@ func getGoogleOIDCParams(cmd *cobra.Command) (*oidcProviderParams, error) {
return params, err
}

func getBootstrapParams(cmd *cobra.Command) (*bootstrapParams, error) {
params := &bootstrapParams{}

var err error

params.sdsURL, err = cmdutils.GetUserSetVarFromString(cmd, sdsURLFlagName, sdsURLEnvKey, false)
if err != nil {
return nil, err
}

params.keyServerURL, err = cmdutils.GetUserSetVarFromString(cmd, keyServerURLFlagName, keyServerURLEnvKey, false)

return params, err
}

func setDefaultLogLevel(userLogLevel string) {
logLevel, err := log.ParseLevel(userLogLevel)
if err != nil {
Expand Down
60 changes: 60 additions & 0 deletions cmd/auth-rest/startcmd/start_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,52 @@ func TestStartCmdWithMissingArg(t *testing.T) {
"Neither host-url (command line flag) nor AUTH_REST_HOST_URL (environment variable) have been set.",
err.Error())
})

t.Run("missing sds url arg", func(t *testing.T) {
oidcURL := mockOIDCProvider(t)
startCmd := GetStartCmd(&mockServer{})

args := []string{
"--" + hostURLFlagName, "localhost:8080",
"--" + logLevelFlagName, log.ParseString(log.DEBUG),
"--" + databaseTypeFlagName, "mem",
"--" + oidcCallbackURLFlagName, "http://example.com/oauth2/callback",
"--" + googleProviderFlagName, oidcURL,
"--" + googleClientIDFlagName, uuid.New().String(),
"--" + googleClientSecretFlagName, uuid.New().String(),
"--" + keyServerURLFlagName, "http://keyserver.example.com",
}
startCmd.SetArgs(args)

err := startCmd.Execute()

require.Error(t, err)
require.Contains(t, err.Error(), sdsURLFlagName)
require.Contains(t, err.Error(), sdsURLEnvKey)
})

t.Run("missing keyserver url arg", func(t *testing.T) {
oidcURL := mockOIDCProvider(t)
startCmd := GetStartCmd(&mockServer{})

args := []string{
"--" + hostURLFlagName, "localhost:8080",
"--" + logLevelFlagName, log.ParseString(log.DEBUG),
"--" + databaseTypeFlagName, "mem",
"--" + oidcCallbackURLFlagName, "http://example.com/oauth2/callback",
"--" + googleProviderFlagName, oidcURL,
"--" + googleClientIDFlagName, uuid.New().String(),
"--" + googleClientSecretFlagName, uuid.New().String(),
"--" + sdsURLFlagName, "http://sds.example.com",
}
startCmd.SetArgs(args)

err := startCmd.Execute()

require.Error(t, err)
require.Contains(t, err.Error(), keyServerURLFlagName)
require.Contains(t, err.Error(), keyServerURLEnvKey)
})
}

func TestStartCmdWithBlankEnvVar(t *testing.T) {
Expand Down Expand Up @@ -164,6 +210,8 @@ func TestStartCmdValidArgs(t *testing.T) {
"--" + googleProviderFlagName, oidcURL,
"--" + googleClientIDFlagName, uuid.New().String(),
"--" + googleClientSecretFlagName, uuid.New().String(),
"--" + sdsURLFlagName, "http://sds.example.com",
"--" + keyServerURLFlagName, "http://keyserver.example.com",
}
startCmd.SetArgs(args)

Expand All @@ -185,6 +233,8 @@ func TestStartCmdValidArgs(t *testing.T) {
"--" + googleClientIDFlagName, uuid.New().String(),
"--" + googleClientSecretFlagName, uuid.New().String(),
"--" + logLevelFlagName, "INVALID",
"--" + sdsURLFlagName, "http://sds.example.com",
"--" + keyServerURLFlagName, "http://keyserver.example.com",
}
startCmd.SetArgs(args)

Expand All @@ -207,6 +257,8 @@ func TestStartCmdValidArgs(t *testing.T) {
"--" + googleProviderFlagName, oidcURL,
"--" + googleClientIDFlagName, uuid.New().String(),
"--" + googleClientSecretFlagName, uuid.New().String(),
"--" + sdsURLFlagName, "http://sds.example.com",
"--" + keyServerURLFlagName, "http://keyserver.example.com",
}
startCmd.SetArgs(args)

Expand All @@ -231,6 +283,8 @@ func TestStartCmdFailToCreateController(t *testing.T) {
"--" + googleProviderFlagName, oidcURL,
"--" + googleClientIDFlagName, uuid.New().String(),
"--" + googleClientSecretFlagName, uuid.New().String(),
"--" + sdsURLFlagName, "http://sds.example.com",
"--" + keyServerURLFlagName, "http://keyserver.example.com",
}
startCmd.SetArgs(args)

Expand All @@ -257,6 +311,8 @@ func TestStartCmdInvalidDatabaseType(t *testing.T) {
"--" + googleProviderFlagName, oidcURL,
"--" + googleClientIDFlagName, uuid.New().String(),
"--" + googleClientSecretFlagName, uuid.New().String(),
"--" + sdsURLFlagName, "http://sds.example.com",
"--" + keyServerURLFlagName, "http://keyserver.example.com",
}
startCmd.SetArgs(args)

Expand Down Expand Up @@ -332,6 +388,10 @@ func setEnvVars(t *testing.T) {
require.NoError(t, err)
err = os.Setenv(googleClientSecretEnvKey, uuid.New().String())
require.NoError(t, err)
err = os.Setenv(sdsURLEnvKey, "http://sds.example.com")
require.NoError(t, err)
err = os.Setenv(keyServerURLEnvKey, "http://keyserver.examepl.com")
require.NoError(t, err)
}

func unsetEnvVars(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/restapi/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func TestController_GetOperations(t *testing.T) {
require.NotNil(t, controller)

ops := controller.GetOperations()
require.Equal(t, 2, len(ops))
require.Equal(t, 3, len(ops))
}

func config(t *testing.T) *operation.Config {
Expand Down
18 changes: 18 additions & 0 deletions pkg/restapi/operation/models.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package operation

type createOIDCRequestResponse struct {
Request string `json:"request"`
}

type bootstrapData struct {
SDSURL string `json:"sdsURL"`
SDSPrimaryVaultID string `json:"sdsPrimaryVaultID"`
KeyServerURL string `json:"keyServerURL"`
KeyStoreIDs []string `json:"keyStoreIDs"`
}
57 changes: 53 additions & 4 deletions pkg/restapi/operation/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ import (
)

const (
oauth2GetRequestPath = "/oauth2/request"
oauth2CallbackPath = "/oauth2/callback"
oauth2GetRequestPath = "/oauth2/request"
oauth2CallbackPath = "/oauth2/callback"
bootstrapGetRequestPath = "/bootstrap"
// api path params
scopeQueryParam = "scope"

Expand Down Expand Up @@ -117,6 +118,7 @@ type Operation struct {
oidcCallbackURL string
oauth2ConfigFunc func(...string) oauth2Config
bootstrapStore storage.Store
bootstrapConfig *BootstrapConfig
}

// Config defines configuration for rp operations.
Expand All @@ -129,10 +131,13 @@ type Config struct {
OIDCCallbackURL string
TransientStoreProvider storage.Provider
StoreProvider storage.Provider
BootstrapConfig *BootstrapConfig
}

type createOIDCRequestResponse struct {
Request string `json:"request"`
// BootstrapConfig holds user bootstrap-related config.
type BootstrapConfig struct {
SDSURL string
KeyServerURL string
}

// New returns rp operation instance.
Expand All @@ -143,6 +148,7 @@ func New(config *Config) (*Operation, error) {
oidcClientID: config.OIDCClientID,
oidcClientSecret: config.OIDCClientSecret,
oidcCallbackURL: config.OIDCCallbackURL,
bootstrapConfig: config.BootstrapConfig,
}

// TODO implement retries: https://github.com/trustbloc/hub-auth/issues/45
Expand Down Expand Up @@ -340,6 +346,48 @@ func (c *Operation) onboardUser(id string) (*user.Profile, error) {
return userProfile, nil
}

func (c *Operation) handleBootstrapDataRequest(w http.ResponseWriter, r *http.Request) {
handle := r.URL.Query().Get("up")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is "up"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DRK3 stands for "user profile", and is being added in #43

if handle == "" {
handleAuthError(w, http.StatusBadRequest, "missing handle")

return
}

profile, err := user.NewStore(c.transientStore).Get(handle)
if errors.Is(err, storage.ErrValueNotFound) {
handleAuthError(w, http.StatusBadRequest, "invalid handle")

return
}

if err != nil {
handleAuthError(w, http.StatusInternalServerError,
fmt.Sprintf("failed to query transient store for handle: %s", err))

return
}

response, err := json.Marshal(&bootstrapData{
SDSURL: c.bootstrapConfig.SDSURL,
SDSPrimaryVaultID: profile.SDSPrimaryVaultID,
KeyServerURL: c.bootstrapConfig.KeyServerURL,
KeyStoreIDs: profile.KeyStoreIDs,
})
if err != nil {
handleAuthError(w, http.StatusInternalServerError, fmt.Sprintf("failed to marshal bootstrap data: %s", err))

return
}

// TODO We should delete the handle from the transient store after writing the response,
// but edge-core store API doesn't have a Delete() operation: https://github.com/trustbloc/edge-core/issues/45
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know if not having the Delete() operation is blocking you and I can work on it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DRK3 it's not blocking for now but should be there if we are going to say this thing is "production-ready"

_, err = w.Write(response)
if err != nil {
logger.Errorf("failed to write bootstrap data to output: %s", err)
}
}

// TODO redirect to the UI: https://github.com/trustbloc/hub-auth/issues/39
func handleAuthResult(w http.ResponseWriter, r *http.Request, _ *user.Profile) {
http.Redirect(w, r, "", http.StatusFound)
Expand Down Expand Up @@ -373,6 +421,7 @@ func (c *Operation) GetRESTHandlers() []Handler {
return []Handler{
support.NewHTTPHandler(oauth2GetRequestPath, http.MethodGet, c.createOIDCRequest),
support.NewHTTPHandler(oauth2CallbackPath, http.MethodGet, c.handleOIDCCallback),
support.NewHTTPHandler(bootstrapGetRequestPath, http.MethodGet, c.handleBootstrapDataRequest),
}
}

Expand Down
Loading