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

Commit c488721

Browse files
committed
feat: setup UI endpoint to serve the UI
closes #39 Signed-off-by: talwinder.kaur <[email protected]>
1 parent 439e45a commit c488721

File tree

4 files changed

+112
-11
lines changed

4 files changed

+112
-11
lines changed

cmd/auth-rest/startcmd/start.go

+35-5
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ const (
7979
" For CouchDB, include the username:password@ text if required." +
8080
" Alternatively, this can be set with the following environment variable: " + databaseURLEnvKey
8181

82+
staticFilesPathFlagName = "static-path"
83+
staticFilesPathFlagUsage = "Path to the folder where the static files are to be hosted under " + uiEndpoint + "." +
84+
"Alternatively, this can be set with the following environment variable: " + staticFilesPathEnvKey
85+
staticFilesPathEnvKey = "AUTH_REST_STATIC_FILES"
86+
8287
databasePrefixFlagName = "database-prefix"
8388
databasePrefixEnvKey = "AUTH_REST_DATABASE_PREFIX"
8489
databasePrefixFlagShorthand = "p"
@@ -129,6 +134,7 @@ const (
129134

130135
const (
131136
// api
137+
uiEndpoint = "/ui"
132138
healthCheckEndpoint = "/healthcheck"
133139
)
134140

@@ -143,6 +149,7 @@ type authRestParameters struct {
143149
tlsParams *tlsParams
144150
oidcParams *oidcParams
145151
bootstrapParams *bootstrapParams
152+
staticFiles string
146153
}
147154

148155
type tlsParams struct {
@@ -210,7 +217,7 @@ func createStartCmd(srv server) *cobra.Command {
210217
}
211218
}
212219

213-
func getAuthRestParameters(cmd *cobra.Command) (*authRestParameters, error) {
220+
func getAuthRestParameters(cmd *cobra.Command) (*authRestParameters, error) { //nolint:funlen,gocyclo
214221
hostURL, err := cmdutils.GetUserSetVarFromString(cmd, hostURLFlagName, hostURLEnvKey, false)
215222
if err != nil {
216223
return nil, err
@@ -231,6 +238,11 @@ func getAuthRestParameters(cmd *cobra.Command) (*authRestParameters, error) {
231238
return nil, err
232239
}
233240

241+
staticFiles, err := cmdutils.GetUserSetVarFromString(cmd, staticFilesPathFlagName, staticFilesPathEnvKey, true)
242+
if err != nil {
243+
return nil, err
244+
}
245+
234246
var databaseURL string
235247
if databaseType == databaseTypeMemOption {
236248
databaseURL = "N/A"
@@ -266,6 +278,7 @@ func getAuthRestParameters(cmd *cobra.Command) (*authRestParameters, error) {
266278
databasePrefix: databasePrefix,
267279
oidcParams: oidcParams,
268280
bootstrapParams: bootstrapParams,
281+
staticFiles: staticFiles,
269282
}, nil
270283
}
271284

@@ -311,6 +324,7 @@ func createFlags(startCmd *cobra.Command) {
311324
startCmd.Flags().StringP(tlsServeCertPathFlagName, "", "", tlsServeCertPathFlagUsage)
312325
startCmd.Flags().StringP(tlsServeKeyPathFlagName, "", "", tlsServeKeyPathFlagUsage)
313326
startCmd.Flags().StringP(logLevelFlagName, logLevelFlagShorthand, "", logLevelPrefixFlagUsage)
327+
startCmd.Flags().StringP(staticFilesPathFlagName, "", "", staticFilesPathFlagUsage)
314328
startCmd.Flags().StringP(databaseTypeFlagName, databaseTypeFlagShorthand, "", databaseTypeFlagUsage)
315329
startCmd.Flags().StringP(databaseURLFlagName, databaseURLFlagShorthand, "", databaseURLFlagUsage)
316330
startCmd.Flags().StringP(databasePrefixFlagName, databasePrefixFlagShorthand, "", databasePrefixFlagUsage)
@@ -340,7 +354,6 @@ func startAuthService(parameters *authRestParameters, srv server) error {
340354
logger.Debugf("root ca's %v", rootCAs)
341355

342356
router := mux.NewRouter()
343-
344357
// health check
345358
router.HandleFunc(healthCheckEndpoint, healthCheckHandler).Methods(http.MethodGet)
346359

@@ -368,12 +381,16 @@ func startAuthService(parameters *authRestParameters, srv server) error {
368381
router.HandleFunc(handler.Path(), handler.Handle()).Methods(handler.Method())
369382
}
370383

371-
logger.Infof(`Starting hub-auth REST server with the following parameters:
372-
Host URL: %s
373-
Database type: %s
384+
logger.Infof(`Starting hub-auth REST server with the following parameters:Host URL: %s Database type: %s
374385
Database URL: %s
375386
Database prefix: %s`, parameters.hostURL, parameters.databaseType, parameters.databaseURL, parameters.databasePrefix)
376387

388+
// static frontend
389+
router.PathPrefix(uiEndpoint).
390+
Subrouter().
391+
Methods(http.MethodGet).
392+
HandlerFunc(uiHandler(parameters.staticFiles, http.ServeFile))
393+
377394
return srv.ListenAndServeTLS(
378395
parameters.hostURL,
379396
parameters.tlsParams.serveCertPath,
@@ -382,6 +399,19 @@ Database prefix: %s`, parameters.hostURL, parameters.databaseType, parameters.da
382399
)
383400
}
384401

402+
func uiHandler(
403+
basePath string,
404+
fileServer func(http.ResponseWriter, *http.Request, string)) func(http.ResponseWriter, *http.Request) {
405+
return func(w http.ResponseWriter, r *http.Request) {
406+
if r.URL.Path == uiEndpoint {
407+
fileServer(w, r, strings.ReplaceAll(basePath+"/index.html", "//", "/"))
408+
return
409+
}
410+
411+
fileServer(w, r, strings.ReplaceAll(basePath+"/"+r.URL.Path[len(uiEndpoint):], "//", "/"))
412+
}
413+
}
414+
385415
func getOIDCParams(cmd *cobra.Command) (*oidcParams, error) {
386416
params := &oidcParams{}
387417

cmd/auth-rest/startcmd/start_test.go

+21
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"fmt"
1212
"net/http"
1313
"net/http/httptest"
14+
"net/url"
1415
"os"
1516
"strings"
1617
"testing"
@@ -197,6 +198,26 @@ func TestStartCmdWithBlankEnvVar(t *testing.T) {
197198
})
198199
}
199200

201+
func TestUIHandler(t *testing.T) {
202+
t.Run("handle base path", func(t *testing.T) {
203+
handled := false
204+
uiHandler(uiEndpoint, func(_ http.ResponseWriter, _ *http.Request, path string) {
205+
handled = true
206+
require.Equal(t, uiEndpoint+"/index.html", path)
207+
})(nil, &http.Request{URL: &url.URL{Path: uiEndpoint}})
208+
require.True(t, handled)
209+
})
210+
t.Run("handle subpaths", func(t *testing.T) {
211+
const expected = uiEndpoint + "/css/abc123.css"
212+
handled := false
213+
uiHandler(uiEndpoint, func(_ http.ResponseWriter, _ *http.Request, path string) {
214+
handled = true
215+
require.Equal(t, expected, path)
216+
})(nil, &http.Request{URL: &url.URL{Path: expected}})
217+
require.True(t, handled)
218+
})
219+
}
220+
200221
func TestStartCmdValidArgs(t *testing.T) {
201222
t.Run("In-memory storage, valid log level", func(t *testing.T) {
202223
oidcURL := mockOIDCProvider(t)

pkg/restapi/operation/operations.go

+31-5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"errors"
1414
"fmt"
1515
"net/http"
16+
"net/url"
1617

1718
"github.com/coreos/go-oidc"
1819
"github.com/google/uuid"
@@ -33,6 +34,9 @@ const (
3334

3435
transientStoreName = "hub-auth-rest-transient"
3536
bootstrapStoreName = "bootstrap-data"
37+
38+
// redirect url parameter
39+
userProfileQueryParam = "up"
3640
)
3741

3842
var logger = log.New("hub-auth-restapi")
@@ -116,6 +120,7 @@ type Operation struct {
116120
oidcClientID string
117121
oidcClientSecret string
118122
oidcCallbackURL string
123+
uiEndpoint string
119124
oauth2ConfigFunc func(...string) oauth2Config
120125
bootstrapStore storage.Store
121126
bootstrapConfig *BootstrapConfig
@@ -129,6 +134,7 @@ type Config struct {
129134
OIDCClientID string
130135
OIDCClientSecret string
131136
OIDCCallbackURL string
137+
UIEndpoint string
132138
TransientStoreProvider storage.Provider
133139
StoreProvider storage.Provider
134140
BootstrapConfig *BootstrapConfig
@@ -329,7 +335,15 @@ func (c *Operation) handleOIDCCallback(w http.ResponseWriter, r *http.Request) {
329335
return
330336
}
331337

332-
handleAuthResult(w, r, userProfile)
338+
profileBytes, err := json.Marshal(userProfile)
339+
if err != nil {
340+
c.writeErrorResponse(w, http.StatusInternalServerError,
341+
fmt.Sprintf("failed to marshal user profile data : %s", err))
342+
343+
return
344+
}
345+
346+
c.handleAuthResult(w, r, profileBytes)
333347
}
334348

335349
// TODO onboard user at key server and SDS: https://github.com/trustbloc/hub-auth/issues/38
@@ -347,7 +361,7 @@ func (c *Operation) onboardUser(id string) (*user.Profile, error) {
347361
}
348362

349363
func (c *Operation) handleBootstrapDataRequest(w http.ResponseWriter, r *http.Request) {
350-
handle := r.URL.Query().Get("up")
364+
handle := r.URL.Query().Get(userProfileQueryParam)
351365
if handle == "" {
352366
handleAuthError(w, http.StatusBadRequest, "missing handle")
353367

@@ -388,9 +402,21 @@ func (c *Operation) handleBootstrapDataRequest(w http.ResponseWriter, r *http.Re
388402
}
389403
}
390404

391-
// TODO redirect to the UI: https://github.com/trustbloc/hub-auth/issues/39
392-
func handleAuthResult(w http.ResponseWriter, r *http.Request, _ *user.Profile) {
393-
http.Redirect(w, r, "", http.StatusFound)
405+
func (c *Operation) handleAuthResult(w http.ResponseWriter, r *http.Request, profileBytes []byte) {
406+
handle := url.QueryEscape(uuid.New().String())
407+
408+
err := c.transientStore.Put(handle, profileBytes)
409+
if err != nil {
410+
c.writeErrorResponse(w,
411+
http.StatusInternalServerError, fmt.Sprintf("failed to write handle to transient store: %s", err))
412+
413+
return
414+
}
415+
416+
redirectURL := fmt.Sprintf("%s?%s=%s", c.uiEndpoint, userProfileQueryParam, handle)
417+
418+
http.Redirect(w, r, redirectURL, http.StatusFound)
419+
logger.Debugf("redirected to: %s", redirectURL)
394420
}
395421

396422
func handleAuthError(w http.ResponseWriter, status int, msg string) {

pkg/restapi/operation/operations_test.go

+25-1
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,30 @@ func TestHandleOIDCCallback(t *testing.T) {
411411
svc.handleOIDCCallback(result, newOIDCCallback(state, "code"))
412412
require.Equal(t, http.StatusInternalServerError, result.Code)
413413
})
414+
t.Run("PUT error while storing user info while handling callback user", func(t *testing.T) {
415+
id := uuid.New().String()
416+
state := uuid.New().String()
417+
config := config(t)
418+
419+
config.TransientStoreProvider = &mockstorage.Provider{
420+
Stores: map[string]storage.Store{
421+
transientStoreName: &mockstore.MockStore{
422+
Store: map[string][]byte{
423+
id: []byte("{}"),
424+
},
425+
ErrGet: storage.ErrValueNotFound,
426+
ErrPut: errors.New("generic"),
427+
},
428+
},
429+
}
430+
431+
svc, err := New(config)
432+
require.NoError(t, err)
433+
434+
result := httptest.NewRecorder()
435+
svc.handleAuthResult(result, newOIDCCallback(state, "code"), nil)
436+
require.Equal(t, http.StatusInternalServerError, result.Code)
437+
})
414438
}
415439

416440
func TestHandleBootstrapDataRequest(t *testing.T) {
@@ -487,7 +511,7 @@ func newOIDCCallback(state, code string) *http.Request {
487511

488512
func newBootstrapDataRequest(handle string) *http.Request {
489513
return httptest.NewRequest(http.MethodGet,
490-
fmt.Sprintf("http://example.com/bootstrap?up=%s", handle), nil)
514+
fmt.Sprintf("http://example.com/bootstrap?%s=%s", userProfileQueryParam,handle), nil)
491515
}
492516

493517
type mockOIDCProvider struct {

0 commit comments

Comments
 (0)