diff options
author | Mike Crute <mike@crute.us> | 2023-07-31 13:34:44 -0700 |
---|---|---|
committer | Mike Crute <mike@crute.us> | 2023-07-31 13:34:44 -0700 |
commit | db217bbb1f74b7aa955d3095fef62c71946768cf (patch) | |
tree | 80ee49b11f137412cf440262950e4a116099eb24 /app | |
parent | 6d867608837f879be2eb934d034f49359f973c84 (diff) | |
download | websocket_proxy-db217bbb1f74b7aa955d3095fef62c71946768cf.tar.bz2 websocket_proxy-db217bbb1f74b7aa955d3095fef62c71946768cf.tar.xz websocket_proxy-db217bbb1f74b7aa955d3095fef62c71946768cf.zip |
Complete registration flow
Diffstat (limited to 'app')
-rw-r--r-- | app/controllers/register.go | 75 |
1 files changed, 71 insertions, 4 deletions
diff --git a/app/controllers/register.go b/app/controllers/register.go index 8698bda..7c1a0f3 100644 --- a/app/controllers/register.go +++ b/app/controllers/register.go | |||
@@ -1,7 +1,13 @@ | |||
1 | package controllers | 1 | package controllers |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "bytes" | ||
5 | "context" | ||
6 | "encoding/json" | ||
7 | "fmt" | ||
8 | "io" | ||
4 | "net/http" | 9 | "net/http" |
10 | "time" | ||
5 | 11 | ||
6 | "code.crute.us/mcrute/golib/echo/session" | 12 | "code.crute.us/mcrute/golib/echo/session" |
7 | "code.crute.us/mcrute/ssh-proxy/app" | 13 | "code.crute.us/mcrute/ssh-proxy/app" |
@@ -19,13 +25,45 @@ type RegisterController[T app.AppSession] struct { | |||
19 | Webauthn *webauthn.WebAuthn | 25 | Webauthn *webauthn.WebAuthn |
20 | } | 26 | } |
21 | 27 | ||
28 | func (a *RegisterController[T]) validateRequest(ctx context.Context, u *models.User, code string) (*models.AuthSession, error) { | ||
29 | if code == "" { | ||
30 | return nil, fmt.Errorf("Code not passed in request") | ||
31 | } | ||
32 | |||
33 | authSession, err := a.AuthSessions.GetByUserCode(ctx, code) | ||
34 | if err != nil { | ||
35 | return nil, fmt.Errorf("No auth session exists") | ||
36 | } | ||
37 | |||
38 | if time.Now().After(authSession.Expires) { | ||
39 | return nil, fmt.Errorf("Session is expired") | ||
40 | } | ||
41 | |||
42 | if !authSession.IsRegistration { | ||
43 | return nil, fmt.Errorf("Session is not an invitation to register") | ||
44 | } | ||
45 | |||
46 | if authSession.UserId != u.Username { | ||
47 | return nil, fmt.Errorf("Session not valid for this user") | ||
48 | } | ||
49 | |||
50 | return authSession, nil | ||
51 | } | ||
52 | |||
22 | func (a *RegisterController[T]) HandleStart(c echo.Context) error { | 53 | func (a *RegisterController[T]) HandleStart(c echo.Context) error { |
23 | user, err := a.Users.Get(c.Request().Context(), c.Param("username")) | 54 | ctx := c.Request().Context() |
55 | |||
56 | user, err := a.Users.Get(ctx, c.Param("username")) | ||
24 | if err != nil { | 57 | if err != nil { |
25 | a.Logger.Errorf("Error getting user: %s", err) | 58 | a.Logger.Errorf("Error getting user: %s", err) |
26 | return c.NoContent(http.StatusNotFound) | 59 | return c.NoContent(http.StatusNotFound) |
27 | } | 60 | } |
28 | 61 | ||
62 | if _, err := a.validateRequest(ctx, user, c.QueryParam("code")); err != nil { | ||
63 | a.Logger.Errorf("Error creating registration request: %s", err) | ||
64 | return c.NoContent(http.StatusNotFound) | ||
65 | } | ||
66 | |||
29 | request, sessionData, err := a.Webauthn.BeginRegistration(user) | 67 | request, sessionData, err := a.Webauthn.BeginRegistration(user) |
30 | if err != nil { | 68 | if err != nil { |
31 | a.Logger.Errorf("Error creating webauthn request: %s", err) | 69 | a.Logger.Errorf("Error creating webauthn request: %s", err) |
@@ -41,13 +79,42 @@ func (a *RegisterController[T]) HandleStart(c echo.Context) error { | |||
41 | } | 79 | } |
42 | 80 | ||
43 | func (a *RegisterController[T]) HandleFinish(c echo.Context) error { | 81 | func (a *RegisterController[T]) HandleFinish(c echo.Context) error { |
44 | user, err := a.Users.Get(c.Request().Context(), c.Param("username")) | 82 | ctx := c.Request().Context() |
83 | |||
84 | body, err := io.ReadAll(c.Request().Body) | ||
85 | if err != nil { | ||
86 | a.Logger.Errorf("Error reading request body:", err) | ||
87 | return c.NoContent(http.StatusInternalServerError) | ||
88 | } | ||
89 | |||
90 | user, err := a.Users.Get(ctx, c.Param("username")) | ||
45 | if err != nil { | 91 | if err != nil { |
46 | a.Logger.Errorf("Error getting user: %s", err) | 92 | a.Logger.Errorf("Error getting user: %s", err) |
47 | return c.NoContent(http.StatusNotFound) | 93 | return c.NoContent(http.StatusNotFound) |
48 | } | 94 | } |
49 | 95 | ||
50 | response, err := protocol.ParseCredentialCreationResponseBody(c.Request().Body) | 96 | var code struct { |
97 | Code string `json:"code"` | ||
98 | } | ||
99 | if err := json.Unmarshal(body, &code); err != nil { | ||
100 | a.Logger.Errorf("Error decoding json body") | ||
101 | return c.NoContent(http.StatusBadRequest) | ||
102 | } | ||
103 | |||
104 | authSession, err := a.validateRequest(ctx, user, code.Code) | ||
105 | if err != nil { | ||
106 | a.Logger.Errorf("Error finishing register request: %s", err) | ||
107 | return c.NoContent(http.StatusNotFound) | ||
108 | } | ||
109 | |||
110 | // Delete before anything else to avoid allowing double use of an auth | ||
111 | // session in case of other errors | ||
112 | if err := a.AuthSessions.Delete(ctx, authSession); err != nil { | ||
113 | a.Logger.Errorf("Error deleting auth session: %s", err) | ||
114 | return c.NoContent(http.StatusInternalServerError) | ||
115 | } | ||
116 | |||
117 | response, err := protocol.ParseCredentialCreationResponseBody(bytes.NewBuffer(body)) | ||
51 | if err != nil { | 118 | if err != nil { |
52 | a.Logger.Errorf("Error parsing credential response: %s", err) | 119 | a.Logger.Errorf("Error parsing credential response: %s", err) |
53 | return c.NoContent(http.StatusBadRequest) | 120 | return c.NoContent(http.StatusBadRequest) |
@@ -69,7 +136,7 @@ func (a *RegisterController[T]) HandleFinish(c echo.Context) error { | |||
69 | 136 | ||
70 | user.Fido2Credentials = append(user.Fido2Credentials, *credential) | 137 | user.Fido2Credentials = append(user.Fido2Credentials, *credential) |
71 | 138 | ||
72 | if err := a.Users.Upsert(c.Request().Context(), user); err != nil { | 139 | if err := a.Users.Upsert(ctx, user); err != nil { |
73 | a.Logger.Errorf("Error saving user: %s", err) | 140 | a.Logger.Errorf("Error saving user: %s", err) |
74 | return c.NoContent(http.StatusInternalServerError) | 141 | return c.NoContent(http.StatusInternalServerError) |
75 | } | 142 | } |