From 8dd46ba48aaeb349877bb10555ad9b06e32298dd Mon Sep 17 00:00:00 2001 From: Ian Ngethe Muchiri <100555904+ianmuchyri@users.noreply.github.com> Date: Thu, 14 Mar 2024 16:16:00 +0300 Subject: [PATCH] MG-217 - Separate refresh token from the session cookie (#218) * separate refresh token from the session Signed-off-by: ianmuchyri * move refresh token from /domains to /domains/login Signed-off-by: ianmuchyri * add refresh token cookie expiry time Signed-off-by: ianmuchyri * remove refresh token cookie in refreshTokenEndpoin Signed-off-by: ianmuchyri * remove http only param Signed-off-by: ianmuchyri * fix fetchData token from accessToken Signed-off-by: ianmuchyri --------- Signed-off-by: ianmuchyri --- ui/api/endpoint.go | 176 +++++++++++++++++++++++------ ui/api/requests.go | 24 ++-- ui/api/transport.go | 161 ++++++++++++++------------ ui/service.go | 102 ++++++++--------- ui/web/templates/login.html | 2 +- ui/web/templates/registration.html | 2 +- 6 files changed, 298 insertions(+), 169 deletions(-) diff --git a/ui/api/endpoint.go b/ui/api/endpoint.go index daab9975..155e4cff 100644 --- a/ui/api/endpoint.go +++ b/ui/api/endpoint.go @@ -107,7 +107,7 @@ func loginEndpoint(svc ui.Service) endpoint.Endpoint { } } -func logoutEndpoint(svc ui.Service) endpoint.Endpoint { +func logoutEndpoint(svc ui.Service, prefix string) endpoint.Endpoint { return func(_ context.Context, _ interface{}) (interface{}, error) { if err := svc.Logout(); err != nil { return nil, err @@ -120,6 +120,18 @@ func logoutEndpoint(svc ui.Service) endpoint.Endpoint { Path: "/", MaxAge: -1, }, + { + Name: refreshTokenKey, + Value: "", + Path: fmt.Sprintf("%s/%s/login", prefix, domainsAPIEndpoint), + MaxAge: -1, + }, + { + Name: refreshTokenKey, + Value: "", + Path: fmt.Sprintf("%s/%s", prefix, tokenRefreshAPIEndpoint), + MaxAge: -1, + }, } return uiRes{ code: http.StatusOK, @@ -213,6 +225,18 @@ func updatePasswordEndpoint(svc ui.Service, prefix string) endpoint.Endpoint { Path: "/", MaxAge: -1, }, + { + Name: refreshTokenKey, + Value: "", + Path: fmt.Sprintf("%s/%s/login", prefix, domainsAPIEndpoint), + MaxAge: -1, + }, + { + Name: refreshTokenKey, + Value: "", + Path: fmt.Sprintf("%s/%s", prefix, tokenRefreshAPIEndpoint), + MaxAge: -1, + }, } return uiRes{ @@ -275,13 +299,16 @@ func secureTokenEndpoint(svc ui.Service, s *securecookie.SecureCookie, prefix st return nil, err } - sessionDetails, err := svc.Session(req.Session) + sessionReq := ui.Session{ + Token: req.AccessToken, + LoginStatus: ui.UserLoginStatus, + } + + sessionDetails, err := svc.Session(sessionReq) if err != nil { return nil, err } - - sessionDetails.Token = req.Token - + sessionDetails.Token = req.AccessToken session, err := json.Marshal(sessionDetails) if err != nil { return nil, err @@ -291,47 +318,70 @@ func secureTokenEndpoint(svc ui.Service, s *securecookie.SecureCookie, prefix st return nil, err } + secureRefreshToken, err := s.Encode(refreshTokenKey, req.RefreshToken) + if err != nil { + return nil, err + } + + refreshExp, err := extractTokenExpiry(req.RefreshToken) + if err != nil { + return nil, err + } + return uiRes{ code: http.StatusSeeOther, cookies: []*http.Cookie{ { - Name: sessionDetailsKey, - Value: secureSessionDetails, - Path: "/", + Name: sessionDetailsKey, + Value: secureSessionDetails, + Path: "/", + HttpOnly: true, }, { - Name: accessTokenKey, - Value: "", - Path: "/", - MaxAge: -1, + Name: refreshTokenKey, + Value: secureRefreshToken, + Path: fmt.Sprintf("%s/%s", prefix, tokenRefreshAPIEndpoint), + Expires: refreshExp, HttpOnly: true, }, { Name: refreshTokenKey, - Value: "", - Path: "/", - MaxAge: -1, + Value: secureRefreshToken, + Path: fmt.Sprintf("%s/%s/login", prefix, domainsAPIEndpoint), + Expires: refreshExp, HttpOnly: true, }, + { + Name: accessTokenKey, + Value: "", + Path: "/", + MaxAge: -1, + }, + { + Name: refreshTokenKey, + Value: "", + Path: "/", + MaxAge: -1, + }, }, headers: map[string]string{"Location": fmt.Sprintf("%s/%s", prefix, domainsAPIEndpoint)}, }, nil } } -func refreshTokenEndpoint(svc ui.Service, s *securecookie.SecureCookie) endpoint.Endpoint { +func refreshTokenEndpoint(svc ui.Service, s *securecookie.SecureCookie, prefix string) endpoint.Endpoint { return func(_ context.Context, request interface{}) (interface{}, error) { req := request.(refreshTokenReq) if err := req.validate(); err != nil { return nil, err } - token, err := svc.RefreshToken(req.RefreshToken) + token, err := svc.RefreshToken(req.Token) if err != nil { return nil, err } - req.Session.Token = token + req.Session.Token = token.AccessToken session, err := json.Marshal(req.Session) if err != nil { return nil, err @@ -341,14 +391,38 @@ func refreshTokenEndpoint(svc ui.Service, s *securecookie.SecureCookie) endpoint return nil, err } + secureRefreshToken, err := s.Encode(refreshTokenKey, token.RefreshToken) + if err != nil { + return nil, err + } + refreshExp, err := extractTokenExpiry(token.RefreshToken) + if err != nil { + return nil, err + } + tkr := uiRes{ code: http.StatusSeeOther, headers: map[string]string{"Location": req.ref}, cookies: []*http.Cookie{ { - Name: sessionDetailsKey, - Value: secureSessionDetails, - Path: "/", + Name: sessionDetailsKey, + Value: secureSessionDetails, + Path: "/", + HttpOnly: true, + }, + { + Name: refreshTokenKey, + Value: secureRefreshToken, + Path: fmt.Sprintf("%s/%s", prefix, tokenRefreshAPIEndpoint), + Expires: refreshExp, + HttpOnly: true, + }, + { + Name: refreshTokenKey, + Value: secureRefreshToken, + Path: fmt.Sprintf("%s/%s/login", prefix, domainsAPIEndpoint), + Expires: refreshExp, + HttpOnly: true, }, }, } @@ -1301,7 +1375,7 @@ func FetchChartDataEndpoint(svc ui.Service) endpoint.Endpoint { if err := req.validate(); err != nil { return nil, err } - res, err := svc.FetchChartData(req.Session.AccessToken, req.channelID, req.mpgm) + res, err := svc.FetchChartData(req.Session.Token, req.channelID, req.mpgm) if err != nil { return nil, err } @@ -1549,18 +1623,18 @@ func domainLoginEndpoint(svc ui.Service, s *securecookie.SecureCookie, prefix st if err := req.validate(); err != nil { return nil, err } - token, err := svc.DomainLogin(req.Login, req.RefreshToken) + token, err := svc.DomainLogin(req.Login, req.Token) if err != nil { return nil, err } req.Domain.ID = req.DomainID - req.AccessToken = token.AccessToken + req.Token = token.AccessToken sessionDetails, err := svc.Session(req.Session) if err != nil { return nil, err } - sessionDetails.Token = token + sessionDetails.Token = token.AccessToken session, err := json.Marshal(sessionDetails) if err != nil { return nil, err @@ -1570,13 +1644,38 @@ func domainLoginEndpoint(svc ui.Service, s *securecookie.SecureCookie, prefix st return nil, err } + secureRefreshToken, err := s.Encode(refreshTokenKey, token.RefreshToken) + if err != nil { + return nil, err + } + + refreshExp, err := extractTokenExpiry(token.RefreshToken) + if err != nil { + return nil, err + } + return uiRes{ code: http.StatusSeeOther, cookies: []*http.Cookie{ { - Name: sessionDetailsKey, - Value: secureSessionDetails, - Path: "/", + Name: sessionDetailsKey, + Value: secureSessionDetails, + Path: "/", + HttpOnly: true, + }, + { + Name: refreshTokenKey, + Value: secureRefreshToken, + Path: fmt.Sprintf("%s/%s", prefix, tokenRefreshAPIEndpoint), + Expires: refreshExp, + HttpOnly: true, + }, + { + Name: refreshTokenKey, + Value: secureRefreshToken, + Path: fmt.Sprintf("%s/%s/login", prefix, domainsAPIEndpoint), + Expires: refreshExp, + HttpOnly: true, }, }, headers: map[string]string{"Location": fmt.Sprintf("%s/?domain=%s", prefix, req.DomainID)}, @@ -1705,11 +1804,22 @@ func disableDomainEndpoint(svc ui.Service, prefix string) endpoint.Endpoint { cookies := []*http.Cookie{ { - Name: accessTokenKey, - Value: "", - Path: "/", - MaxAge: -1, - HttpOnly: true, + Name: sessionDetailsKey, + Value: "", + Path: "/", + MaxAge: -1, + }, + { + Name: refreshTokenKey, + Value: "", + Path: fmt.Sprintf("%s/%s", prefix, tokenRefreshAPIEndpoint), + MaxAge: -1, + }, + { + Name: refreshTokenKey, + Value: "", + Path: fmt.Sprintf("%s/%s/login", prefix, domainsAPIEndpoint), + MaxAge: -1, }, } diff --git a/ui/api/requests.go b/ui/api/requests.go index 30db5426..f9477efa 100644 --- a/ui/api/requests.go +++ b/ui/api/requests.go @@ -24,7 +24,7 @@ type indexReq struct { } func (req indexReq) validate() error { - if req.AccessToken == "" { + if req.Token == "" { return errInvalidCredentials } return nil @@ -62,7 +62,7 @@ func (req tokenReq) validate() error { } type secureTokenReq struct { - ui.Session + sdk.Token } func (req secureTokenReq) validate() error { @@ -81,7 +81,7 @@ type refreshTokenReq struct { } func (req refreshTokenReq) validate() error { - if req.RefreshToken == "" { + if req.Token == "" { return errMissingRefreshToken } if req.ref == "" { @@ -137,7 +137,7 @@ type listEntityReq struct { } func (req listEntityReq) validate() error { - if req.AccessToken == "" { + if req.Token == "" { return errInvalidCredentials } if req.page == 0 { @@ -158,7 +158,7 @@ type listEntityByIDReq struct { } func (req listEntityByIDReq) validate() error { - if req.AccessToken == "" { + if req.Token == "" { return errInvalidCredentials } if req.id == "" { @@ -179,7 +179,7 @@ type viewResourceReq struct { } func (req viewResourceReq) validate() error { - if req.AccessToken == "" { + if req.Token == "" { return errInvalidCredentials } if req.id == "" { @@ -659,7 +659,7 @@ type readMessagesReq struct { } func (req readMessagesReq) validate() error { - if req.AccessToken == "" && req.thingKey == "" { + if req.Token == "" && req.thingKey == "" { return errInvalidCredentials } if req.channelID == "" { @@ -889,7 +889,7 @@ type domainLoginReq struct { } func (req domainLoginReq) validate() error { - if req.AccessToken == "" { + if req.Token == "" { return errAuthentication } if req.DomainID == "" { @@ -906,7 +906,7 @@ type listDomainsReq struct { } func (req listDomainsReq) validate() error { - if req.Token.AccessToken == "" { + if req.Token == "" { return errAuthentication } if req.page == 0 { @@ -1010,7 +1010,7 @@ type viewMemberReq struct { } func (req viewMemberReq) validate() error { - if req.AccessToken == "" { + if req.Token == "" { return errAuthentication } if req.userIdentity == "" { @@ -1086,7 +1086,7 @@ type listInvitationsReq struct { } func (req listInvitationsReq) validate() error { - if req.AccessToken == "" { + if req.Token == "" { return errAuthentication } if req.page == 0 { @@ -1105,7 +1105,7 @@ type viewDashboardReq struct { } func (req viewDashboardReq) validate() error { - if req.AccessToken == "" { + if req.Token == "" { return errInvalidCredentials } return nil diff --git a/ui/api/transport.go b/ui/api/transport.go index 455df567..82d7013c 100644 --- a/ui/api/transport.go +++ b/ui/api/transport.go @@ -137,7 +137,7 @@ func MakeHandler(svc ui.Service, r *chi.Mux, instanceID, prefix string, secureCo ).ServeHTTP) r.Get("/token/refresh", kithttp.NewServer( - refreshTokenEndpoint(svc, secureCookie), + refreshTokenEndpoint(svc, secureCookie, prefix), decodeRefreshTokenRequest(secureCookie), encodeResponse, opts..., @@ -151,7 +151,7 @@ func MakeHandler(svc ui.Service, r *chi.Mux, instanceID, prefix string, secureCo ).ServeHTTP) r.Get("/logout", kithttp.NewServer( - logoutEndpoint(svc), + logoutEndpoint(svc, prefix), decodeLogoutRequest, encodeResponse, opts..., @@ -777,7 +777,7 @@ func MakeHandler(svc ui.Service, r *chi.Mux, instanceID, prefix string, secureCo r.Route("/domains", func(r chi.Router) { r.Post("/login", kithttp.NewServer( domainLoginEndpoint(svc, secureCookie, prefix), - decodeDomainLoginRequest, + decodeDomainLoginRequest(secureCookie), encodeResponse, opts..., ).ServeHTTP) @@ -905,7 +905,7 @@ func decodeCreateDashboardRequest(_ context.Context, r *http.Request) (interface } return createDashboardReq{ - token: session.AccessToken, + token: session.Token, Name: data.Name, Description: data.Description, }, nil @@ -928,7 +928,7 @@ func decodeListDashboardsRequest(_ context.Context, r *http.Request) (interface{ } return listDashboardsReq{ - token: session.AccessToken, + token: session.Token, page: page, limit: limit, }, nil @@ -955,7 +955,7 @@ func decodeUpdateDashboardRequest(_ context.Context, r *http.Request) (interface } return updateDashboardReq{ - token: session.AccessToken, + token: session.Token, ID: data.ID, Name: data.Name, Description: data.Description, @@ -975,7 +975,7 @@ func decodeDeleteDashboardRequest(_ context.Context, r *http.Request) (interface } return deleteDashboardReq{ - token: session.AccessToken, + token: session.Token, ID: data.ID, }, nil } @@ -1012,7 +1012,7 @@ func decodePasswordUpdate(_ context.Context, r *http.Request) (interface{}, erro return nil, err } return updateUserPasswordReq{ - token: session.AccessToken, + token: session.Token, oldPass: r.PostFormValue("oldpass"), newPass: r.PostFormValue("newpass"), }, nil @@ -1072,16 +1072,11 @@ func decodeSecureTokenRequest(_ context.Context, r *http.Request) (interface{}, return nil, err } - session := ui.Session{ + return secureTokenReq{ Token: sdk.Token{ AccessToken: accessToken, RefreshToken: refreshToken, }, - LoginStatus: ui.UserLoginStatus, - } - - return secureTokenReq{ - Session: session, }, nil } @@ -1091,6 +1086,11 @@ func decodeRefreshTokenRequest(s *securecookie.SecureCookie) kithttp.DecodeReque if err != nil { return nil, err } + refreshTokenCookie, err := tokenFromCookie(r, refreshTokenKey) + if err != nil { + return nil, err + } + var session string if err := s.Decode(sessionDetailsKey, sessionCookie, &session); err != nil { return nil, err @@ -1099,6 +1099,13 @@ func decodeRefreshTokenRequest(s *securecookie.SecureCookie) kithttp.DecodeReque if err := json.Unmarshal([]byte(session), &sessionDetails); err != nil { return ui.Session{}, err } + + var refreshToken string + if err := s.Decode(refreshTokenKey, refreshTokenCookie, &refreshToken); err != nil { + return ui.Session{}, err + } + sessionDetails.Token = refreshToken + referer, err := readStringQuery(r, refererKey, defKey) if err != nil { return nil, err @@ -1162,7 +1169,7 @@ func decodeUserCreation(_ context.Context, r *http.Request) (interface{}, error) } return createUserReq{ - token: session.AccessToken, + token: session.Token, User: user, }, nil } @@ -1227,7 +1234,7 @@ func decodeUsersCreation(_ context.Context, r *http.Request) (interface{}, error } return createUsersReq{ - token: session.AccessToken, + token: session.Token, users: users, }, nil } @@ -1256,7 +1263,7 @@ func decodeUserUpdate(_ context.Context, r *http.Request) (interface{}, error) { user.ID = chi.URLParam(r, "id") return updateUserReq{ - token: session.AccessToken, + token: session.Token, User: user, }, nil } @@ -1273,7 +1280,7 @@ func decodeUserTagsUpdate(_ context.Context, r *http.Request) (interface{}, erro user.ID = chi.URLParam(r, "id") return updateUserTagsReq{ - token: session.AccessToken, + token: session.Token, User: user, }, nil } @@ -1289,7 +1296,7 @@ func decodeUserIdentityUpdate(_ context.Context, r *http.Request) (interface{}, } return updateUserIdentityReq{ - token: session.AccessToken, + token: session.Token, User: sdk.User{ ID: chi.URLParam(r, "id"), Credentials: credentials, @@ -1303,7 +1310,7 @@ func decodeUserStatusUpdate(_ context.Context, r *http.Request) (interface{}, er return nil, err } return updateUserStatusReq{ - token: session.AccessToken, + token: session.Token, id: r.PostFormValue("entityID"), }, nil } @@ -1314,7 +1321,7 @@ func decodeUserRoleUpdate(_ context.Context, r *http.Request) (interface{}, erro return nil, err } return updateUserRoleReq{ - token: session.AccessToken, + token: session.Token, User: sdk.User{ ID: chi.URLParam(r, "id"), Role: r.PostFormValue("role"), @@ -1332,7 +1339,7 @@ func decodeAssignGroupRequest(_ context.Context, r *http.Request) (interface{}, } return assignReq{ - token: session.AccessToken, + token: session.Token, groupID: chi.URLParam(r, "id"), UsersRelationRequest: sdk.UsersRelationRequest{ UserIDs: r.Form["userID"], @@ -1351,7 +1358,7 @@ func decodeShareThingRequest(_ context.Context, r *http.Request) (interface{}, e } return shareThingReq{ - token: session.AccessToken, + token: session.Token, id: chi.URLParam(r, "id"), UsersRelationRequest: sdk.UsersRelationRequest{ UserIDs: r.Form["userID"], @@ -1370,7 +1377,7 @@ func decodeAddMemberToChannelRequest(_ context.Context, r *http.Request) (interf } return addUserToChannelReq{ - token: session.AccessToken, + token: session.Token, ChannelID: chi.URLParam(r, "id"), UsersRelationRequest: sdk.UsersRelationRequest{ Relation: r.Form.Get("relation"), @@ -1394,7 +1401,7 @@ func decodeThingCreation(_ context.Context, r *http.Request) (interface{}, error } return createThingReq{ - token: session.AccessToken, + token: session.Token, Thing: sdk.Thing{ Name: r.PostFormValue("name"), ID: r.PostFormValue("thingID"), @@ -1420,7 +1427,7 @@ func decodeThingUpdate(_ context.Context, r *http.Request) (interface{}, error) thing.ID = chi.URLParam(r, "id") return updateThingReq{ - token: session.AccessToken, + token: session.Token, Thing: thing, }, nil } @@ -1437,7 +1444,7 @@ func decodeThingTagsUpdate(_ context.Context, r *http.Request) (interface{}, err thing.ID = chi.URLParam(r, "id") return updateThingTagsReq{ - token: session.AccessToken, + token: session.Token, Thing: thing, }, nil } @@ -1453,7 +1460,7 @@ func decodeThingSecretUpdate(_ context.Context, r *http.Request) (interface{}, e } return updateThingSecretReq{ - token: session.AccessToken, + token: session.Token, Thing: sdk.Thing{ ID: chi.URLParam(r, "id"), Credentials: credentials, @@ -1467,7 +1474,7 @@ func decodeThingStatusUpdate(_ context.Context, r *http.Request) (interface{}, e return nil, err } return updateThingStatusReq{ - token: session.AccessToken, + token: session.Token, id: r.PostFormValue("entityID"), }, nil } @@ -1536,7 +1543,7 @@ func decodeThingsCreation(_ context.Context, r *http.Request) (interface{}, erro } return createThingsReq{ - token: session.AccessToken, + token: session.Token, things: things, }, nil } @@ -1559,7 +1566,7 @@ func decodeChannelCreation(_ context.Context, r *http.Request) (interface{}, err } return createChannelReq{ - token: session.AccessToken, + token: session.Token, Channel: ch, }, nil } @@ -1616,7 +1623,7 @@ func decodeChannelsCreation(_ context.Context, r *http.Request) (interface{}, er } return createChannelsReq{ - token: session.AccessToken, + token: session.Token, Channels: channels, }, nil } @@ -1633,7 +1640,7 @@ func decodeChannelUpdate(_ context.Context, r *http.Request) (interface{}, error channel.ID = chi.URLParam(r, "id") return updateChannelReq{ - token: session.AccessToken, + token: session.Token, Channel: channel, }, nil } @@ -1657,14 +1664,14 @@ func decodeConnectChannel(_ context.Context, r *http.Request) (interface{}, erro switch item { case thingsItem: req = connectThingReq{ - token: session.AccessToken, + token: session.Token, channelID: r.Form.Get("channelID"), thingID: chi.URLParam(r, "id"), item: item, } case channelsItem: req = connectThingReq{ - token: session.AccessToken, + token: session.Token, channelID: chi.URLParam(r, "id"), thingID: r.Form.Get("thingID"), item: item, @@ -1680,7 +1687,7 @@ func decodeChannelStatusUpdate(_ context.Context, r *http.Request) (interface{}, return nil, err } return updateChannelStatusReq{ - token: session.AccessToken, + token: session.Token, id: r.PostFormValue("entityID"), }, nil } @@ -1700,7 +1707,7 @@ func decodeAddGroupToChannelRequest(_ context.Context, r *http.Request) (interfa } req := addUserGroupToChannelReq{ - token: session.AccessToken, + token: session.Token, item: item, } @@ -1727,7 +1734,7 @@ func decodeGroupCreation(_ context.Context, r *http.Request) (interface{}, error } return createGroupReq{ - token: session.AccessToken, + token: session.Token, Group: sdk.Group{ Name: r.PostFormValue("name"), Description: r.PostFormValue("description"), @@ -1789,7 +1796,7 @@ func decodeGroupsCreation(_ context.Context, r *http.Request) (interface{}, erro } return createGroupsReq{ - token: session.AccessToken, + token: session.Token, Groups: groups, }, nil } @@ -1807,7 +1814,7 @@ func decodeGroupUpdate(_ context.Context, r *http.Request) (interface{}, error) group.ID = chi.URLParam(r, "id") return updateGroupReq{ - token: session.AccessToken, + token: session.Token, Group: group, }, nil } @@ -1818,7 +1825,7 @@ func decodeGroupStatusUpdate(_ context.Context, r *http.Request) (interface{}, e return nil, err } return updateGroupStatusReq{ - token: session.AccessToken, + token: session.Token, id: r.PostFormValue("entityID"), }, nil } @@ -1958,7 +1965,7 @@ func decodeTerminalCommandRequest(_ context.Context, r *http.Request) (interface return nil, err } return bootstrapCommandReq{ - token: session.AccessToken, + token: session.Token, id: chi.URLParam(r, "id"), command: strings.ReplaceAll(strings.Trim(r.PostFormValue("command"), " "), " ", ","), }, nil @@ -1974,7 +1981,7 @@ func decodeCreateBootstrapRequest(_ context.Context, r *http.Request) (interface } return createBootstrapReq{ - token: session.AccessToken, + token: session.Token, BootstrapConfig: sdk.BootstrapConfig{ ThingID: r.FormValue("thingID"), ExternalID: r.FormValue("externalID"), @@ -2002,7 +2009,7 @@ func decodeUpdateBootstrap(_ context.Context, r *http.Request) (interface{}, err config.ThingID = chi.URLParam(r, "id") return updateBootstrapReq{ - token: session.AccessToken, + token: session.Token, BootstrapConfig: config, }, nil } @@ -2013,7 +2020,7 @@ func decodeDeleteBootstrap(_ context.Context, r *http.Request) (interface{}, err return nil, err } return deleteBootstrapReq{ - token: session.AccessToken, + token: session.Token, id: chi.URLParam(r, "id"), }, nil } @@ -2029,7 +2036,7 @@ func decodeUpdateBootstrapState(_ context.Context, r *http.Request) (interface{} } return updateBootstrapStateReq{ - token: session.AccessToken, + token: session.Token, BootstrapConfig: sdk.BootstrapConfig{ ThingID: chi.URLParam(r, "id"), State: state, @@ -2049,7 +2056,7 @@ func decodeUpdateBootstrapCerts(_ context.Context, r *http.Request) (interface{} config.ThingID = chi.URLParam(r, "id") return updateBootstrapCertReq{ - token: session.AccessToken, + token: session.Token, BootstrapConfig: config, }, nil } @@ -2064,7 +2071,7 @@ func decodeUpdateBootstrapConnections(_ context.Context, r *http.Request) (inter } return updateBootstrapConnReq{ - token: session.AccessToken, + token: session.Token, BootstrapConfig: sdk.BootstrapConfig{ ThingID: chi.URLParam(r, "id"), Channels: r.PostForm["channelID"], @@ -2166,7 +2173,7 @@ func decodeGetEntitiesRequest(_ context.Context, r *http.Request) (interface{}, } return getEntitiesReq{ - token: session.AccessToken, + token: session.Token, item: item, page: page, name: name, @@ -2176,19 +2183,31 @@ func decodeGetEntitiesRequest(_ context.Context, r *http.Request) (interface{}, }, nil } -func decodeDomainLoginRequest(_ context.Context, r *http.Request) (interface{}, error) { - session, err := sessionFromHeader(r) - if err != nil { - return nil, err - } - session.LoginStatus = ui.DomainLoginStatus +func decodeDomainLoginRequest(s *securecookie.SecureCookie) kithttp.DecodeRequestFunc { + return func(_ context.Context, r *http.Request) (interface{}, error) { + refreshTokenCookie, err := tokenFromCookie(r, refreshTokenKey) + if err != nil { + return nil, err + } + var refreshToken string + if err := s.Decode(refreshTokenKey, refreshTokenCookie, &refreshToken); err != nil { + return ui.Session{}, err + } - return domainLoginReq{ - Session: session, - Login: sdk.Login{ - DomainID: r.FormValue("domainID"), - }, - }, nil + session, err := sessionFromHeader(r) + if err != nil { + return nil, err + } + session.LoginStatus = ui.DomainLoginStatus + session.Token = refreshToken + + return domainLoginReq{ + Session: session, + Login: sdk.Login{ + DomainID: r.FormValue("domainID"), + }, + }, nil + } } func decodeListDomainsRequest(_ context.Context, r *http.Request) (interface{}, error) { @@ -2237,7 +2256,7 @@ func decodeCreateDomainRequest(_ context.Context, r *http.Request) (interface{}, } return createDomainReq{ - token: session.AccessToken, + token: session.Token, Domain: sdk.Domain{ Name: r.FormValue("name"), Alias: r.FormValue("alias"), @@ -2259,7 +2278,7 @@ func decodeUpdateDomainRequest(_ context.Context, r *http.Request) (interface{}, domain.ID = chi.URLParam(r, "id") return updateDomainReq{ - token: session.AccessToken, + token: session.Token, Domain: domain, }, nil } @@ -2276,7 +2295,7 @@ func decodeUpdateDomainTagsRequest(_ context.Context, r *http.Request) (interfac domain.ID = chi.URLParam(r, "id") return updateDomainTagsReq{ - token: session.AccessToken, + token: session.Token, Domain: domain, }, nil } @@ -2287,7 +2306,7 @@ func decodeDomainStatusUpdate(_ context.Context, r *http.Request) (interface{}, return nil, err } return updateDomainStatusReq{ - token: session.AccessToken, + token: session.Token, id: r.PostFormValue("entityID"), }, nil } @@ -2302,7 +2321,7 @@ func decodeAssignMemberRequest(_ context.Context, r *http.Request) (interface{}, } return assignMemberReq{ - token: session.AccessToken, + token: session.Token, domainID: chi.URLParam(r, "id"), UsersRelationRequest: sdk.UsersRelationRequest{ UserIDs: r.Form["userID"], @@ -2334,7 +2353,7 @@ func decodeSendInvitationRequest(_ context.Context, r *http.Request) (interface{ return nil, err } return sendInvitationReq{ - token: session.AccessToken, + token: session.Token, Invitation: sdk.Invitation{ DomainID: r.PostFormValue("domainID"), UserID: r.PostFormValue("userID"), @@ -2382,7 +2401,7 @@ func decodeAcceptInvitationRequest(_ context.Context, r *http.Request) (interfac } return acceptInvitationReq{ - token: session.AccessToken, + token: session.Token, domainID: r.Form.Get("domainID"), }, nil } @@ -2402,7 +2421,7 @@ func decodeDeleteInvitationRequest(_ context.Context, r *http.Request) (interfac } return deleteInvitationReq{ - token: session.AccessToken, + token: session.Token, domain: domain, domainID: r.Form.Get("domainID"), userID: r.Form.Get("userID"), @@ -2539,7 +2558,7 @@ func TokenMiddleware(prefix string) func(http.Handler) http.Handler { } // Parse the token without validation to get the expiration time - token, _, err := new(jwt.Parser).ParseUnverified(session.AccessToken, jwt.MapClaims{}) + token, _, err := new(jwt.Parser).ParseUnverified(session.Token, jwt.MapClaims{}) if err != nil { http.Redirect(w, r, fmt.Sprintf("%s/%s?error=%s", prefix, errorAPIEndpoint, url.QueryEscape(err.Error())), http.StatusSeeOther) return @@ -2564,7 +2583,7 @@ func AuthnMiddleware(prefix string) func(http.Handler) http.Handler { return } - token, _, err := new(jwt.Parser).ParseUnverified(session.AccessToken, jwt.MapClaims{}) + token, _, err := new(jwt.Parser).ParseUnverified(session.Token, jwt.MapClaims{}) if err != nil { http.Redirect(w, r, fmt.Sprintf("%s/%s?error=%s", prefix, errorAPIEndpoint, url.QueryEscape(err.Error())), http.StatusSeeOther) return diff --git a/ui/service.go b/ui/service.go index bea8833a..a0f519d9 100644 --- a/ui/service.go +++ b/ui/service.go @@ -109,7 +109,7 @@ type Session struct { User User `json:"user"` Domain Domain `json:"domain"` LoginStatus LoginStatus `json:"login_status"` - sdk.Token `json:"token"` + Token string `json:"token"` } var ( @@ -409,42 +409,42 @@ func (us *uiService) Index(s Session) (b []byte, err error) { Status: enabled, } - users, err := us.sdk.Users(pgm, s.AccessToken) + users, err := us.sdk.Users(pgm, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } - things, err := us.sdk.Things(pgm, s.AccessToken) + things, err := us.sdk.Things(pgm, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } - groups, err := us.sdk.Groups(pgm, s.AccessToken) + groups, err := us.sdk.Groups(pgm, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } - channels, err := us.sdk.Channels(pgm, s.AccessToken) + channels, err := us.sdk.Channels(pgm, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } - enabledUsers, err := us.sdk.Users(enabledPgm, s.AccessToken) + enabledUsers, err := us.sdk.Users(enabledPgm, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } - enabledThings, err := us.sdk.Things(enabledPgm, s.AccessToken) + enabledThings, err := us.sdk.Things(enabledPgm, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } - enabledGroups, err := us.sdk.Groups(enabledPgm, s.AccessToken) + enabledGroups, err := us.sdk.Groups(enabledPgm, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } - enabledChannels, err := us.sdk.Channels(enabledPgm, s.AccessToken) + enabledChannels, err := us.sdk.Channels(enabledPgm, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } @@ -604,7 +604,7 @@ func (us *uiService) DomainLogin(login sdk.Login, refreshToken string) (t sdk.To } func (us *uiService) Session(s Session) (Session, error) { - user, err := us.sdk.UserProfile(s.AccessToken) + user, err := us.sdk.UserProfile(s.Token) if err != nil { return Session{}, err } @@ -620,11 +620,11 @@ func (us *uiService) Session(s Session) (Session, error) { } if s.LoginStatus == DomainLoginStatus { - domain, err := us.sdk.Domain(s.Domain.ID, s.AccessToken) + domain, err := us.sdk.Domain(s.Domain.ID, s.Token) if err != nil { return Session{}, err } - permissions, err := us.sdk.DomainPermissions(s.Domain.ID, s.AccessToken) + permissions, err := us.sdk.DomainPermissions(s.Domain.ID, s.Token) if err != nil { return Session{}, err } @@ -655,7 +655,7 @@ func (us *uiService) ListUsers(s Session, status string, page, limit uint64) ([] Limit: limit, Status: status, } - users, err := us.sdk.Users(pgm, s.AccessToken) + users, err := us.sdk.Users(pgm, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } @@ -699,7 +699,7 @@ func (us *uiService) ListUsers(s Session, status string, page, limit uint64) ([] } func (us *uiService) ViewUser(s Session, id string) (b []byte, err error) { - user, err := us.sdk.User(id, s.AccessToken) + user, err := us.sdk.User(id, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } @@ -807,7 +807,7 @@ func (us *uiService) ListThings(s Session, status string, page, limit uint64) ([ Limit: limit, Status: status, } - things, err := us.sdk.Things(pgm, s.AccessToken) + things, err := us.sdk.Things(pgm, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } @@ -849,12 +849,12 @@ func (us *uiService) ListThings(s Session, status string, page, limit uint64) ([ } func (us *uiService) ViewThing(s Session, id string) (b []byte, err error) { - thing, err := us.sdk.Thing(id, s.AccessToken) + thing, err := us.sdk.Thing(id, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } - permissions, err := us.sdk.ThingPermissions(id, s.AccessToken) + permissions, err := us.sdk.ThingPermissions(id, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } @@ -955,12 +955,12 @@ func (us *uiService) ListThingUsers(s Session, id, relation string, page, limit Limit: limit, Permission: relation, } - usersPage, err := us.sdk.ListThingUsers(id, pgm, s.AccessToken) + usersPage, err := us.sdk.ListThingUsers(id, pgm, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } - permissions, err := us.sdk.ThingPermissions(id, s.AccessToken) + permissions, err := us.sdk.ThingPermissions(id, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } @@ -1015,17 +1015,17 @@ func (us *uiService) ListChannelsByThing(s Session, id string, page, limit uint6 Visibility: statusAll, } - chsPage, err := us.sdk.ChannelsByThing(id, pgm, s.AccessToken) + chsPage, err := us.sdk.ChannelsByThing(id, pgm, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } - permissions, err := us.sdk.ThingPermissions(id, s.AccessToken) + permissions, err := us.sdk.ThingPermissions(id, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } - thing, err := us.sdk.Thing(id, s.AccessToken) + thing, err := us.sdk.Thing(id, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } @@ -1093,7 +1093,7 @@ func (us *uiService) ListChannels(s Session, status string, page, limit uint64) Limit: limit, Status: status, } - chsPage, err := us.sdk.Channels(pgm, s.AccessToken) + chsPage, err := us.sdk.Channels(pgm, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } @@ -1137,12 +1137,12 @@ func (us *uiService) ListChannels(s Session, status string, page, limit uint64) } func (us *uiService) ViewChannel(s Session, channelID string) (b []byte, err error) { - channel, err := us.sdk.Channel(channelID, s.AccessToken) + channel, err := us.sdk.Channel(channelID, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } - permissions, err := us.sdk.ChannelPermissions(channelID, s.AccessToken) + permissions, err := us.sdk.ChannelPermissions(channelID, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } @@ -1196,12 +1196,12 @@ func (us *uiService) ListThingsByChannel(s Session, channelID string, page, limi Visibility: statusAll, } - thsPage, err := us.sdk.ThingsByChannel(channelID, pgm, s.AccessToken) + thsPage, err := us.sdk.ThingsByChannel(channelID, pgm, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } - permissions, err := us.sdk.ChannelPermissions(channelID, s.AccessToken) + permissions, err := us.sdk.ChannelPermissions(channelID, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } @@ -1315,12 +1315,12 @@ func (us *uiService) ListChannelUsers(s Session, id, relation string, page, limi Limit: limit, Permission: relation, } - usersPage, err := us.sdk.ListChannelUsers(id, pgm, s.AccessToken) + usersPage, err := us.sdk.ListChannelUsers(id, pgm, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } - permissions, err := us.sdk.ChannelPermissions(id, s.AccessToken) + permissions, err := us.sdk.ChannelPermissions(id, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } @@ -1390,12 +1390,12 @@ func (us *uiService) ListChannelUserGroups(s Session, id string, page, limit uin Offset: offset, Limit: limit, } - groupsPage, err := us.sdk.ListChannelUserGroups(id, pgm, s.AccessToken) + groupsPage, err := us.sdk.ListChannelUserGroups(id, pgm, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } - permissions, err := us.sdk.ChannelPermissions(id, s.AccessToken) + permissions, err := us.sdk.ChannelPermissions(id, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } @@ -1462,12 +1462,12 @@ func (us *uiService) ListGroupUsers(s Session, id, relation string, page, limit Permission: relation, } - usersPage, err := us.sdk.ListGroupUsers(id, pgm, s.AccessToken) + usersPage, err := us.sdk.ListGroupUsers(id, pgm, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } - permissions, err := us.sdk.GroupPermissions(id, s.AccessToken) + permissions, err := us.sdk.GroupPermissions(id, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } @@ -1532,17 +1532,17 @@ func (us *uiService) Unassign(token, groupID string, userRelation sdk.UsersRelat } func (us *uiService) ViewGroup(s Session, id string) (b []byte, err error) { - group, err := us.sdk.Group(id, s.AccessToken) + group, err := us.sdk.Group(id, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } - parent, err := us.sdk.Group(group.ParentID, s.AccessToken) + parent, err := us.sdk.Group(group.ParentID, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } - permissions, err := us.sdk.GroupPermissions(id, s.AccessToken) + permissions, err := us.sdk.GroupPermissions(id, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } @@ -1595,7 +1595,7 @@ func (us *uiService) ListGroups(s Session, status string, page, limit uint64) ([ Limit: limit, Status: status, } - grpPage, err := us.sdk.Groups(pgm, s.AccessToken) + grpPage, err := us.sdk.Groups(pgm, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } @@ -1660,12 +1660,12 @@ func (us *uiService) ListUserGroupChannels(s Session, id string, page, limit uin Offset: offset, Limit: limit, } - channelsPage, err := us.sdk.ListGroupChannels(id, pgm, s.AccessToken) + channelsPage, err := us.sdk.ListGroupChannels(id, pgm, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } - permissions, err := us.sdk.GroupPermissions(id, s.AccessToken) + permissions, err := us.sdk.GroupPermissions(id, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } @@ -1713,7 +1713,7 @@ func (us *uiService) ListUserGroupChannels(s Session, id string, page, limit uin } func (us *uiService) ReadMessages(s Session, channelID, thingKey string, mpgm sdk.MessagePageMetadata) ([]byte, error) { - msg, err := us.sdk.ReadMessages(mpgm, channelID, s.AccessToken) + msg, err := us.sdk.ReadMessages(mpgm, channelID, s.Token) if err != nil { return []byte{}, err } @@ -1805,7 +1805,7 @@ func (us *uiService) ListBootstrap(s Session, page, limit uint64) ([]byte, error Visibility: statusAll, } - bootstraps, err := us.sdk.Bootstraps(pgm, s.AccessToken) + bootstraps, err := us.sdk.Bootstraps(pgm, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } @@ -1816,7 +1816,7 @@ func (us *uiService) ListBootstrap(s Session, page, limit uint64) ([]byte, error Limit: uint64(100), } - things, err := us.sdk.Things(filter, s.AccessToken) + things, err := us.sdk.Things(filter, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } @@ -1897,7 +1897,7 @@ func (us *uiService) UpdateBootstrapState(token string, config sdk.BootstrapConf } func (us *uiService) ViewBootstrap(s Session, thingID string) ([]byte, error) { - bootstrap, err := us.sdk.ViewBootstrap(thingID, s.AccessToken) + bootstrap, err := us.sdk.ViewBootstrap(thingID, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } @@ -1917,7 +1917,7 @@ func (us *uiService) ViewBootstrap(s Session, thingID string) ([]byte, error) { return nil, errors.Wrap(errors.New("invalid channels"), ErrFailedRetreive) } - thing, err := us.sdk.Thing(thingID, s.AccessToken) + thing, err := us.sdk.Thing(thingID, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } @@ -2143,7 +2143,7 @@ func (us *uiService) ListDomains(s Session, status string, page, limit uint64) ( Status: status, } - domainsPage, err := us.sdk.Domains(pgm, s.AccessToken) + domainsPage, err := us.sdk.Domains(pgm, s.Token) if err != nil { return []byte{}, errors.Wrap(ErrFailedRetreive, err) } @@ -2197,12 +2197,12 @@ func (us *uiService) UpdateDomain(token string, domain sdk.Domain) error { } func (us *uiService) Domain(s Session) ([]byte, error) { - domain, err := us.sdk.Domain(s.Domain.ID, s.AccessToken) + domain, err := us.sdk.Domain(s.Domain.ID, s.Token) if err != nil { return []byte{}, errors.Wrap(ErrFailedRetreive, err) } - permissions, err := us.sdk.DomainPermissions(s.Domain.ID, s.AccessToken) + permissions, err := us.sdk.DomainPermissions(s.Domain.ID, s.Token) if err != nil { return []byte{}, errors.Wrap(ErrFailedRetreive, err) } @@ -2273,7 +2273,7 @@ func (us *uiService) ViewMember(s Session, userIdentity string) (b []byte, err e pgm := sdk.PageMetadata{ Identity: userIdentity, } - usersPage, err := us.sdk.Users(pgm, s.AccessToken) + usersPage, err := us.sdk.Users(pgm, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } @@ -2313,7 +2313,7 @@ func (us *uiService) Members(s Session, page, limit uint64) ([]byte, error) { Limit: limit, } - membersPage, err := us.sdk.ListDomainUsers(s.Domain.ID, pgm, s.AccessToken) + membersPage, err := us.sdk.ListDomainUsers(s.Domain.ID, pgm, s.Token) if err != nil { return []byte{}, err } @@ -2367,7 +2367,7 @@ func (us *uiService) Invitations(s Session, domainID string, page, limit uint64) DomainID: domainID, State: statePending, } - invitationsPage, err := us.sdk.Invitations(pgm, s.AccessToken) + invitationsPage, err := us.sdk.Invitations(pgm, s.Token) if err != nil { return []byte{}, errors.Wrap(err, ErrFailedRetreive) } @@ -2469,7 +2469,7 @@ func (us *uiService) ViewDashboard(s Session, dashboardID string) ([]byte, error var btpl bytes.Buffer charts := CreateItem() - user, sdkerr := us.sdk.UserProfile(s.AccessToken) + user, sdkerr := us.sdk.UserProfile(s.Token) if sdkerr != nil { return btpl.Bytes(), errors.Wrap(ErrFailedRetrieveUserID, sdkerr) } diff --git a/ui/web/templates/login.html b/ui/web/templates/login.html index 9c530bf0..eb2aa669 100644 --- a/ui/web/templates/login.html +++ b/ui/web/templates/login.html @@ -76,7 +76,7 @@

Login

or sign in with:

diff --git a/ui/web/templates/registration.html b/ui/web/templates/registration.html index cb89de55..b108f7a2 100644 --- a/ui/web/templates/registration.html +++ b/ui/web/templates/registration.html @@ -80,7 +80,7 @@

Register

or sign up with: