From c7a1f94972c02d8fb4e0fd101711281b98fe394e Mon Sep 17 00:00:00 2001 From: Denis Arh Date: Mon, 24 Sep 2018 13:20:18 +0200 Subject: [PATCH] remove user creation and login endpoints --- auth/docs/src/spec.json | 28 +----- auth/rest/auth.go | 53 ------------ auth/rest/handlers/auth.go | 67 --------------- auth/rest/oidc.go | 4 +- auth/rest/request/auth.go | 141 ------------------------------- auth/rest/request/misc.go | 10 --- auth/rest/router.go | 41 +++++++-- auth/start.go | 3 + codegen.sh | 4 +- internal/auth/jwt.go | 22 +++-- sam/docs/README.md | 39 +-------- sam/docs/src/spec.json | 34 -------- sam/docs/src/spec/auth.json | 68 --------------- sam/repository/repository.go | 5 +- sam/rest/auth.go | 66 --------------- sam/rest/handlers/auth.go | 67 --------------- sam/rest/handlers/auth_custom.go | 76 ----------------- sam/rest/request/auth.go | 141 ------------------------------- sam/rest/router.go | 7 -- 19 files changed, 56 insertions(+), 820 deletions(-) delete mode 100644 auth/rest/auth.go delete mode 100644 auth/rest/handlers/auth.go delete mode 100644 auth/rest/request/auth.go delete mode 100644 auth/rest/request/misc.go delete mode 100644 sam/docs/src/spec/auth.json delete mode 100644 sam/rest/auth.go delete mode 100644 sam/rest/handlers/auth.go delete mode 100644 sam/rest/handlers/auth_custom.go delete mode 100644 sam/rest/request/auth.go diff --git a/auth/docs/src/spec.json b/auth/docs/src/spec.json index 79cf67c72..2109e4dc1 100644 --- a/auth/docs/src/spec.json +++ b/auth/docs/src/spec.json @@ -5,32 +5,6 @@ "path": "/auth", "entrypoint": "auth", "authentication": [], - "apis": [ - { - "name": "login", - "method": "POST", - "title": "User login", - "parameters": { - "post": [ - { "type": "string", "name": "username", "required": true, "title": "Username or email" }, - { "type": "string", "name": "password", "required": true, "title": "Password for user" } - ] - } - }, - { - "name": "create", - "path": "/create", - "method": "POST", - "title": "Create new user", - "parameters": { - "post": [ - { "type": "string", "name": "name", "required": true, "title": "Display name" }, - { "type": "string", "name": "email", "required": true, "title": "Email" }, - { "type": "string", "name": "username", "required": true, "title": "Username" }, - { "type": "string", "name": "password", "required": true, "title": "Password" } - ] - } - } - ] + "apis": [] } ] diff --git a/auth/rest/auth.go b/auth/rest/auth.go deleted file mode 100644 index f757cd772..000000000 --- a/auth/rest/auth.go +++ /dev/null @@ -1,53 +0,0 @@ -package rest - -import ( - "context" - - "github.com/pkg/errors" - - "github.com/crusttech/crust/auth/rest/request" - "github.com/crusttech/crust/auth/service" - "github.com/crusttech/crust/auth/types" - "github.com/crusttech/crust/internal/auth" -) - -var _ = errors.Wrap - -type ( - Auth struct { - user service.UserService - token auth.TokenEncoder - } -) - -func (Auth) New(credValidator service.UserService, tknEncoder auth.TokenEncoder) *Auth { - return &Auth{ - credValidator, - tknEncoder, - } -} - -func (ctrl *Auth) Login(ctx context.Context, r *request.AuthLogin) (interface{}, error) { - return ctrl.tokenize(ctrl.user.With(ctx).ValidateCredentials(r.Username, r.Password)) -} - -func (ctrl *Auth) Create(ctx context.Context, r *request.AuthCreate) (interface{}, error) { - user := &types.User{Username: r.Username} - user.GeneratePassword(r.Password) - return ctrl.tokenize(ctrl.user.With(ctx).Create(user)) -} - -// Wraps user return value and appends JWT -func (ctrl *Auth) tokenize(user *types.User, err error) (interface{}, error) { - if err != nil { - return nil, err - } - - return struct { - JWT string - User *types.User `json:"user"` - }{ - JWT: ctrl.token.Encode(user), - User: user, - }, nil -} diff --git a/auth/rest/handlers/auth.go b/auth/rest/handlers/auth.go deleted file mode 100644 index 956ca98a2..000000000 --- a/auth/rest/handlers/auth.go +++ /dev/null @@ -1,67 +0,0 @@ -package handlers - -/* - Hello! This file is auto-generated from `docs/src/spec.json`. - - For development: - In order to update the generated files, edit this file under the location, - add your struct fields, imports, API definitions and whatever you want, and: - - 1. run [spec](https://github.com/titpetric/spec) in the same folder, - 2. run `./_gen.php` in this folder. - - You may edit `auth.go`, `auth.util.go` or `auth_test.go` to - implement your API calls, helper functions and tests. The file `auth.go` - is only generated the first time, and will not be overwritten if it exists. -*/ - -import ( - "context" - "github.com/go-chi/chi" - "net/http" - - "github.com/titpetric/factory/resputil" - - "github.com/crusttech/crust/auth/rest/request" -) - -// Internal API interface -type AuthAPI interface { - Login(context.Context, *request.AuthLogin) (interface{}, error) - Create(context.Context, *request.AuthCreate) (interface{}, error) -} - -// HTTP API interface -type Auth struct { - Login func(http.ResponseWriter, *http.Request) - Create func(http.ResponseWriter, *http.Request) -} - -func NewAuth(ah AuthAPI) *Auth { - return &Auth{ - Login: func(w http.ResponseWriter, r *http.Request) { - defer r.Body.Close() - params := request.NewAuthLogin() - resputil.JSON(w, params.Fill(r), func() (interface{}, error) { - return ah.Login(r.Context(), params) - }) - }, - Create: func(w http.ResponseWriter, r *http.Request) { - defer r.Body.Close() - params := request.NewAuthCreate() - resputil.JSON(w, params.Fill(r), func() (interface{}, error) { - return ah.Create(r.Context(), params) - }) - }, - } -} - -func (ah *Auth) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.Handler) { - r.Group(func(r chi.Router) { - r.Use(middlewares...) - r.Route("/auth", func(r chi.Router) { - r.Post("/login", ah.Login) - r.Post("/create", ah.Create) - }) - }) -} diff --git a/auth/rest/oidc.go b/auth/rest/oidc.go index 2c3dc84da..27d6cb2f5 100644 --- a/auth/rest/oidc.go +++ b/auth/rest/oidc.go @@ -36,7 +36,7 @@ type ( jwtEncodeCookieSetter interface { auth.TokenEncoder - SetToCookie(w http.ResponseWriter, r *http.Request, identity auth.Identifiable) + SetCookie(w http.ResponseWriter, r *http.Request, identity auth.Identifiable) } ) @@ -162,7 +162,7 @@ func (c *openIdConnect) HandleOAuth2Callback(w http.ResponseWriter, r *http.Requ resputil.JSON(w, err) return } else { - c.jwt.SetToCookie(w, r, user) + c.jwt.SetCookie(w, r, user) } http.Redirect(w, r, c.appURL, http.StatusSeeOther) diff --git a/auth/rest/request/auth.go b/auth/rest/request/auth.go deleted file mode 100644 index a061884bd..000000000 --- a/auth/rest/request/auth.go +++ /dev/null @@ -1,141 +0,0 @@ -package request - -/* - Hello! This file is auto-generated from `docs/src/spec.json`. - - For development: - In order to update the generated files, edit this file under the location, - add your struct fields, imports, API definitions and whatever you want, and: - - 1. run [spec](https://github.com/titpetric/spec) in the same folder, - 2. run `./_gen.php` in this folder. - - You may edit `auth.go`, `auth.util.go` or `auth_test.go` to - implement your API calls, helper functions and tests. The file `auth.go` - is only generated the first time, and will not be overwritten if it exists. -*/ - -import ( - "encoding/json" - "github.com/go-chi/chi" - "github.com/jmoiron/sqlx/types" - "github.com/pkg/errors" - "io" - "mime/multipart" - "net/http" - "strings" -) - -var _ = chi.URLParam -var _ = types.JSONText{} -var _ = multipart.FileHeader{} - -// Auth login request parameters -type AuthLogin struct { - Username string - Password string -} - -func NewAuthLogin() *AuthLogin { - return &AuthLogin{} -} - -func (a *AuthLogin) Fill(r *http.Request) error { - var err error - - if strings.ToLower(r.Header.Get("content-type")) == "application/json" { - err = json.NewDecoder(r.Body).Decode(a) - - switch { - case err == io.EOF: - err = nil - case err != nil: - return errors.Wrap(err, "error parsing http request body") - } - } - - r.ParseForm() - get := map[string]string{} - post := map[string]string{} - urlQuery := r.URL.Query() - for name, param := range urlQuery { - get[name] = string(param[0]) - } - postVars := r.Form - for name, param := range postVars { - post[name] = string(param[0]) - } - - if val, ok := post["username"]; ok { - - a.Username = val - } - if val, ok := post["password"]; ok { - - a.Password = val - } - - return err -} - -var _ RequestFiller = NewAuthLogin() - -// Auth create request parameters -type AuthCreate struct { - Name string - Email string - Username string - Password string -} - -func NewAuthCreate() *AuthCreate { - return &AuthCreate{} -} - -func (a *AuthCreate) Fill(r *http.Request) error { - var err error - - if strings.ToLower(r.Header.Get("content-type")) == "application/json" { - err = json.NewDecoder(r.Body).Decode(a) - - switch { - case err == io.EOF: - err = nil - case err != nil: - return errors.Wrap(err, "error parsing http request body") - } - } - - r.ParseForm() - get := map[string]string{} - post := map[string]string{} - urlQuery := r.URL.Query() - for name, param := range urlQuery { - get[name] = string(param[0]) - } - postVars := r.Form - for name, param := range postVars { - post[name] = string(param[0]) - } - - if val, ok := post["name"]; ok { - - a.Name = val - } - if val, ok := post["email"]; ok { - - a.Email = val - } - if val, ok := post["username"]; ok { - - a.Username = val - } - if val, ok := post["password"]; ok { - - a.Password = val - } - - return err -} - -var _ RequestFiller = NewAuthCreate() diff --git a/auth/rest/request/misc.go b/auth/rest/request/misc.go deleted file mode 100644 index 9992cfd73..000000000 --- a/auth/rest/request/misc.go +++ /dev/null @@ -1,10 +0,0 @@ -package request - -import ( - "net/http" -) - -// RequestFiller is an interface for typed request parameters -type RequestFiller interface { - Fill(r *http.Request) error -} diff --git a/auth/rest/router.go b/auth/rest/router.go index 58226f3b8..d077025f8 100644 --- a/auth/rest/router.go +++ b/auth/rest/router.go @@ -6,17 +6,24 @@ import ( "net/http" "github.com/crusttech/crust/auth/repository" + "github.com/crusttech/crust/auth/types" + "github.com/crusttech/crust/internal/auth" "github.com/go-chi/chi" "github.com/titpetric/factory/resputil" - "github.com/crusttech/crust/auth/rest/handlers" "github.com/crusttech/crust/auth/service" "github.com/crusttech/crust/internal/config" ) +type ( + checkResponse struct { + JWT string `json:"jwt"` + User *types.User `json:"user"` + } +) + func MountRoutes(oidcConfig *config.OIDC, jwtAuth jwtEncodeCookieSetter) func(chi.Router) { var userSvc = service.User() - var ctx = context.Background() oidc, err := OpenIdConnect(ctx, oidcConfig, userSvc, jwtAuth, repository.NewSettings(ctx)) @@ -26,8 +33,6 @@ func MountRoutes(oidcConfig *config.OIDC, jwtAuth jwtEncodeCookieSetter) func(ch // Initialize handers & controllers. return func(r chi.Router) { - handlers.NewAuth(Auth{}.New(userSvc, jwtAuth)).MountRoutes(r) - if oidc != nil { r.Route("/oidc", func(r chi.Router) { r.Get("/", oidc.HandleRedirect) @@ -35,12 +40,30 @@ func MountRoutes(oidcConfig *config.OIDC, jwtAuth jwtEncodeCookieSetter) func(ch }) } - r.Get("/jwt", func(w http.ResponseWriter, r *http.Request) { - if c, err := r.Cookie("jwt"); err != nil { - resputil.JSON(w, "") - } else { - resputil.JSON(w, c.Value) + r.Get("/check", func(w http.ResponseWriter, r *http.Request) { + if c, err := r.Cookie("jwt"); err == nil { + ctx := r.Context() + + if identity := auth.GetIdentityFromContext(ctx); identity != nil && identity.Valid() { + if user, err := service.DefaultUser.With(ctx).FindByID(identity.Identity()); err == nil { + resputil.JSON(w, checkResponse{ + JWT: c.Value, + User: user, + }) + + return + } + } + + // Did not send response, assuming invalid cookie + jwtAuth.SetCookie(w, r, nil) } + + resputil.JSON(w, "") + }) + + r.Delete("/check", func(w http.ResponseWriter, r *http.Request) { + jwtAuth.SetCookie(w, r, nil) }) } } diff --git a/auth/start.go b/auth/start.go index d2ba6eca5..c6fd7ad16 100644 --- a/auth/start.go +++ b/auth/start.go @@ -8,6 +8,7 @@ import ( "github.com/SentimensRG/ctx/sigctx" "github.com/crusttech/crust/auth/rest" + "github.com/crusttech/crust/auth/service" "github.com/go-chi/chi" "github.com/go-chi/cors" "github.com/pkg/errors" @@ -46,6 +47,8 @@ func Init() error { }, }) + service.Init() + return nil } diff --git a/codegen.sh b/codegen.sh index 553c3b1db..a1459f242 100755 --- a/codegen.sh +++ b/codegen.sh @@ -3,7 +3,7 @@ set -e function gofmt { echo "=== fmt all folders ===" - GOPATHS=$(find -name '*.go' | grep -v vendor/ | xargs -n1 dirname | sort | uniq) + GOPATHS=$(find . -name '*.go' | grep -v vendor/ | xargs -n1 dirname | sort | uniq) for FOLDER in $GOPATHS; do #echo "== go fmt $FOLDER ==" cd $FOLDER @@ -26,4 +26,4 @@ for SPEC in $SPECS; do codegen/codegen.php $(basename $SRC) | tee -a /dev/stderr done -gofmt \ No newline at end of file +gofmt diff --git a/internal/auth/jwt.go b/internal/auth/jwt.go index 14a91a528..96220802f 100644 --- a/internal/auth/jwt.go +++ b/internal/auth/jwt.go @@ -69,16 +69,20 @@ func (t *jwt) Authenticator() func(http.Handler) http.Handler { } // Extracts and authenticates JWT from context, validates claims -func (t *jwt) SetToCookie(w http.ResponseWriter, r *http.Request, identity Identifiable) { - // Store state to cookie as well - http.SetCookie(w, &http.Cookie{ - Name: "jwt", - Value: t.Encode(identity), - +func (t *jwt) SetCookie(w http.ResponseWriter, r *http.Request, identity Identifiable) { + cookie := &http.Cookie{ + Name: "jwt", Expires: time.Now().Add(time.Duration(t.expiry) * time.Minute), + Secure: r.URL.Scheme == "https", Domain: t.cookieDomain, + Path: "/", + } - Secure: r.URL.Scheme == "https", - Path: "/", - }) + if identity == nil { + cookie.Expires = time.Unix(0, 0) + } else { + cookie.Value = t.Encode(identity) + } + + http.SetCookie(w, cookie) } diff --git a/sam/docs/README.md b/sam/docs/README.md index f6319a039..074978265 100644 --- a/sam/docs/README.md +++ b/sam/docs/README.md @@ -614,41 +614,4 @@ The following event types may be sent with a message event: | Parameter | Type | Method | Description | Default | Required? | | --------- | ---- | ------ | ----------- | ------- | --------- | | userID | uint64 | PATH | User ID | N/A | YES | -| message | string | POST | Message contents (markdown) | N/A | YES | - - - - -# Authentication - -## User login - -#### Method - -| URI | Protocol | Method | Authentication | -| --- | -------- | ------ | -------------- | -| `/auth/login` | HTTP/S | POST | | - -#### Request parameters - -| Parameter | Type | Method | Description | Default | Required? | -| --------- | ---- | ------ | ----------- | ------- | --------- | -| username | string | POST | Username or email | N/A | YES | -| password | string | POST | Password for user | N/A | YES | - -## Create new user - -#### Method - -| URI | Protocol | Method | Authentication | -| --- | -------- | ------ | -------------- | -| `/auth/create` | HTTP/S | POST | | - -#### Request parameters - -| Parameter | Type | Method | Description | Default | Required? | -| --------- | ---- | ------ | ----------- | ------- | --------- | -| name | string | POST | Display name | N/A | YES | -| email | string | POST | Email | N/A | YES | -| username | string | POST | Username | N/A | YES | -| password | string | POST | Password | N/A | YES | \ No newline at end of file +| message | string | POST | Message contents (markdown) | N/A | YES | \ No newline at end of file diff --git a/sam/docs/src/spec.json b/sam/docs/src/spec.json index ea8cf472c..518955f6e 100644 --- a/sam/docs/src/spec.json +++ b/sam/docs/src/spec.json @@ -533,39 +533,5 @@ } } ] - }, - { - "title": "Authentication", - "package": "sam", - "path": "/auth", - "entrypoint": "auth", - "authentication": [], - "apis": [ - { - "name": "login", - "method": "POST", - "title": "User login", - "parameters": { - "post": [ - { "type": "string", "name": "username", "required": true, "title": "Username or email" }, - { "type": "string", "name": "password", "required": true, "title": "Password for user" } - ] - } - }, - { - "name": "create", - "path": "/create", - "method": "POST", - "title": "Create new user", - "parameters": { - "post": [ - { "type": "string", "name": "name", "required": true, "title": "Display name" }, - { "type": "string", "name": "email", "required": true, "title": "Email" }, - { "type": "string", "name": "username", "required": true, "title": "Username" }, - { "type": "string", "name": "password", "required": true, "title": "Password" } - ] - } - } - ] } ] diff --git a/sam/docs/src/spec/auth.json b/sam/docs/src/spec/auth.json deleted file mode 100644 index 07fd7562a..000000000 --- a/sam/docs/src/spec/auth.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "Title": "Authentication", - "Package": "sam", - "Interface": "Auth", - "Struct": null, - "Parameters": null, - "Protocol": "", - "Authentication": [], - "Path": "/auth", - "APIs": [ - { - "Name": "login", - "Method": "POST", - "Title": "User login", - "Path": "/login", - "Parameters": { - "post": [ - { - "name": "username", - "required": true, - "title": "Username or email", - "type": "string" - }, - { - "name": "password", - "required": true, - "title": "Password for user", - "type": "string" - } - ] - } - }, - { - "Name": "create", - "Method": "POST", - "Title": "Create new user", - "Path": "/create", - "Parameters": { - "post": [ - { - "name": "name", - "required": true, - "title": "Display name", - "type": "string" - }, - { - "name": "email", - "required": true, - "title": "Email", - "type": "string" - }, - { - "name": "username", - "required": true, - "title": "Username", - "type": "string" - }, - { - "name": "password", - "required": true, - "title": "Password", - "type": "string" - } - ] - } - } - ] -} \ No newline at end of file diff --git a/sam/repository/repository.go b/sam/repository/repository.go index 17dee4fe0..82b20e4ef 100644 --- a/sam/repository/repository.go +++ b/sam/repository/repository.go @@ -18,8 +18,8 @@ type ( ) var ( -_db *factory.DB -_ctx context.Context + _db *factory.DB + _ctx context.Context ) // DB returns a repository-wide singleton DB handle @@ -56,7 +56,6 @@ func (r *repository) Context() context.Context { return r.ctx } - // db returns context-aware db handle func (r *repository) db() *factory.DB { return r.dbh(r.ctx) diff --git a/sam/rest/auth.go b/sam/rest/auth.go deleted file mode 100644 index d89a8b6a3..000000000 --- a/sam/rest/auth.go +++ /dev/null @@ -1,66 +0,0 @@ -package rest - -import ( - "context" - "github.com/crusttech/crust/auth/service" - "github.com/crusttech/crust/auth/types" - "github.com/crusttech/crust/internal/auth" - "github.com/crusttech/crust/sam/rest/request" - "github.com/pkg/errors" -) - -var _ = errors.Wrap - -type ( - Auth struct { - svc struct { - user service.UserService - token auth.TokenEncoder - } - } - - authPayload struct { - JWT string - User *types.User `json:"user"` - } - - authUserBasics interface { - ValidateCredentials(ctx context.Context, username, password string) (*types.User, error) - Create(ctx context.Context, input *types.User) (user *types.User, err error) - } -) - -func (Auth) New(tknEncoder auth.TokenEncoder) *Auth { - ctrl := &Auth{} - ctrl.svc.user = service.DefaultUser - ctrl.svc.token = tknEncoder - - return ctrl -} - -func (ctrl *Auth) Login(ctx context.Context, r *request.AuthLogin) (interface{}, error) { - return ctrl.tokenize(ctrl.svc.user.ValidateCredentials(r.Username, r.Password)) -} - -func (ctrl *Auth) Create(ctx context.Context, r *request.AuthCreate) (interface{}, error) { - user := &types.User{Username: r.Username} - user.GeneratePassword(r.Password) - - return ctrl.tokenize(ctrl.svc.user.With(ctx).Create(user)) -} - -// Wraps user return value and appends JWT -func (ctrl *Auth) tokenize(user *types.User, err error) (interface{}, error) { - if err != nil { - return nil, err - } - - return &authPayload{ - JWT: ctrl.svc.token.Encode(user), - User: user, - }, nil -} - -func (ap authPayload) Token() string { - return ap.JWT -} diff --git a/sam/rest/handlers/auth.go b/sam/rest/handlers/auth.go deleted file mode 100644 index fed3f92c1..000000000 --- a/sam/rest/handlers/auth.go +++ /dev/null @@ -1,67 +0,0 @@ -package handlers - -/* - Hello! This file is auto-generated from `docs/src/spec.json`. - - For development: - In order to update the generated files, edit this file under the location, - add your struct fields, imports, API definitions and whatever you want, and: - - 1. run [spec](https://github.com/titpetric/spec) in the same folder, - 2. run `./_gen.php` in this folder. - - You may edit `auth.go`, `auth.util.go` or `auth_test.go` to - implement your API calls, helper functions and tests. The file `auth.go` - is only generated the first time, and will not be overwritten if it exists. -*/ - -import ( - "context" - "github.com/go-chi/chi" - "net/http" - - "github.com/titpetric/factory/resputil" - - "github.com/crusttech/crust/sam/rest/request" -) - -// Internal API interface -type AuthAPI interface { - Login(context.Context, *request.AuthLogin) (interface{}, error) - Create(context.Context, *request.AuthCreate) (interface{}, error) -} - -// HTTP API interface -type Auth struct { - Login func(http.ResponseWriter, *http.Request) - Create func(http.ResponseWriter, *http.Request) -} - -func NewAuth(ah AuthAPI) *Auth { - return &Auth{ - Login: func(w http.ResponseWriter, r *http.Request) { - defer r.Body.Close() - params := request.NewAuthLogin() - resputil.JSON(w, params.Fill(r), func() (interface{}, error) { - return ah.Login(r.Context(), params) - }) - }, - Create: func(w http.ResponseWriter, r *http.Request) { - defer r.Body.Close() - params := request.NewAuthCreate() - resputil.JSON(w, params.Fill(r), func() (interface{}, error) { - return ah.Create(r.Context(), params) - }) - }, - } -} - -func (ah *Auth) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.Handler) { - r.Group(func(r chi.Router) { - r.Use(middlewares...) - r.Route("/auth", func(r chi.Router) { - r.Post("/login", ah.Login) - r.Post("/create", ah.Create) - }) - }) -} diff --git a/sam/rest/handlers/auth_custom.go b/sam/rest/handlers/auth_custom.go deleted file mode 100644 index 962a8636a..000000000 --- a/sam/rest/handlers/auth_custom.go +++ /dev/null @@ -1,76 +0,0 @@ -package handlers - -/* - Hello! This file is auto-generated from `docs/src/spec.json`. - - For development: - In order to update the generated files, edit this file under the location, - add your struct fields, imports, API definitions and whatever you want, and: - - 1. run [spec](https://github.com/titpetric/spec) in the same folder, - 2. run `./_gen.php` in this folder. - - You may edit `auth.go`, `auth.util.go` or `auth_test.go` to - implement your API calls, helper functions and tests. The file `auth.go` - is only generated the first time, and will not be overwritten if it exists. -*/ - -import ( - "net/http" - - "github.com/titpetric/factory/resputil" - - "github.com/crusttech/crust/sam/rest/request" - "net/url" - "time" -) - -type ( - authPayload interface { - Token() string - } -) - -// Initializies custom auth handler that attaches cookie info -// -// Cookie with JWT is added on successful login or user creation -// -func NewAuthCustom(ah AuthAPI, cookieExp int) *Auth { - setCookie := func(w http.ResponseWriter, reqUrl *url.URL) func(payload interface{}, err error) (interface{}, error) { - return func(payload interface{}, err error) (interface{}, error) { - if ap, ok := payload.(authPayload); ok && err == nil { - http.SetCookie(w, &http.Cookie{ - Name: "jwt", - Value: ap.Token(), - - HttpOnly: false, // we need this for attachments & ws! - Secure: reqUrl.Scheme == "https", - Path: "/", - //Domain: "localhost", - - // @todo read from the config file. - Expires: time.Now().Add(time.Duration(cookieExp) * time.Minute), - }) - } - - return payload, err - } - } - - return &Auth{ - Login: func(w http.ResponseWriter, r *http.Request) { - defer r.Body.Close() - params := request.NewAuthLogin() - resputil.JSON(w, params.Fill(r), func() (interface{}, error) { - return setCookie(w, r.URL)(ah.Login(r.Context(), params)) - }) - }, - Create: func(w http.ResponseWriter, r *http.Request) { - defer r.Body.Close() - params := request.NewAuthCreate() - resputil.JSON(w, params.Fill(r), func() (interface{}, error) { - return setCookie(w, r.URL)(ah.Create(r.Context(), params)) - }) - }, - } -} diff --git a/sam/rest/request/auth.go b/sam/rest/request/auth.go deleted file mode 100644 index a061884bd..000000000 --- a/sam/rest/request/auth.go +++ /dev/null @@ -1,141 +0,0 @@ -package request - -/* - Hello! This file is auto-generated from `docs/src/spec.json`. - - For development: - In order to update the generated files, edit this file under the location, - add your struct fields, imports, API definitions and whatever you want, and: - - 1. run [spec](https://github.com/titpetric/spec) in the same folder, - 2. run `./_gen.php` in this folder. - - You may edit `auth.go`, `auth.util.go` or `auth_test.go` to - implement your API calls, helper functions and tests. The file `auth.go` - is only generated the first time, and will not be overwritten if it exists. -*/ - -import ( - "encoding/json" - "github.com/go-chi/chi" - "github.com/jmoiron/sqlx/types" - "github.com/pkg/errors" - "io" - "mime/multipart" - "net/http" - "strings" -) - -var _ = chi.URLParam -var _ = types.JSONText{} -var _ = multipart.FileHeader{} - -// Auth login request parameters -type AuthLogin struct { - Username string - Password string -} - -func NewAuthLogin() *AuthLogin { - return &AuthLogin{} -} - -func (a *AuthLogin) Fill(r *http.Request) error { - var err error - - if strings.ToLower(r.Header.Get("content-type")) == "application/json" { - err = json.NewDecoder(r.Body).Decode(a) - - switch { - case err == io.EOF: - err = nil - case err != nil: - return errors.Wrap(err, "error parsing http request body") - } - } - - r.ParseForm() - get := map[string]string{} - post := map[string]string{} - urlQuery := r.URL.Query() - for name, param := range urlQuery { - get[name] = string(param[0]) - } - postVars := r.Form - for name, param := range postVars { - post[name] = string(param[0]) - } - - if val, ok := post["username"]; ok { - - a.Username = val - } - if val, ok := post["password"]; ok { - - a.Password = val - } - - return err -} - -var _ RequestFiller = NewAuthLogin() - -// Auth create request parameters -type AuthCreate struct { - Name string - Email string - Username string - Password string -} - -func NewAuthCreate() *AuthCreate { - return &AuthCreate{} -} - -func (a *AuthCreate) Fill(r *http.Request) error { - var err error - - if strings.ToLower(r.Header.Get("content-type")) == "application/json" { - err = json.NewDecoder(r.Body).Decode(a) - - switch { - case err == io.EOF: - err = nil - case err != nil: - return errors.Wrap(err, "error parsing http request body") - } - } - - r.ParseForm() - get := map[string]string{} - post := map[string]string{} - urlQuery := r.URL.Query() - for name, param := range urlQuery { - get[name] = string(param[0]) - } - postVars := r.Form - for name, param := range postVars { - post[name] = string(param[0]) - } - - if val, ok := post["name"]; ok { - - a.Name = val - } - if val, ok := post["email"]; ok { - - a.Email = val - } - if val, ok := post["username"]; ok { - - a.Username = val - } - if val, ok := post["password"]; ok { - - a.Password = val - } - - return err -} - -var _ RequestFiller = NewAuthCreate() diff --git a/sam/rest/router.go b/sam/rest/router.go index 6b14421fd..df2e2d8cb 100644 --- a/sam/rest/router.go +++ b/sam/rest/router.go @@ -9,13 +9,6 @@ import ( func MountRoutes(jwtAuth auth.TokenEncoder) func(chi.Router) { // Initialize handers & controllers. return func(r chi.Router) { - // Cookie expiration in minutes - // @todo pull this from auth/jwt config - var cookieExp = 3600 - - handlers.NewAuthCustom(Auth{}.New(jwtAuth), cookieExp).MountRoutes(r) - - // @todo solve cookie issues ( handlers.NewAttachmentDownloadable(Attachment{}.New()).MountRoutes(r) // Protect all _private_ routes