Files
netmaker/pro/auth/register_callback.go
T
Abhishek K 2e8d95e80e NET-1227: User Mgmt V2 (#3055)
* user mgmt models

* define user roles

* define models for new user mgmt and groups

* oauth debug log

* initialize user role after db conn

* print oauth token in debug log

* user roles CRUD apis

* user groups CRUD Apis

* additional api checks

* add additional scopes

* add additional scopes url

* add additional scopes url

* rm additional scopes url

* setup middlleware permission checks

* integrate permission check into middleware

* integrate permission check into middleware

* check for headers for subjects

* refactor user role models

* refactor user groups models

* add new user to pending user via RAC login

* untracked

* allow multiple groups for an user

* change json tag

* add debug headers

* refer network controls form roles, add debug headers

* refer network controls form roles, add debug headers

* replace auth checks, add network id to role model

* nodes handler

* migration funcs

* invoke sync users migration func

* add debug logs

* comment middleware

* fix get all nodes api

* add debug logs

* fix middleware error nil check

* add new func to get username from jwt

* fix jwt parsing

* abort on error

* allow multiple network roles

* allow multiple network roles

* add migration func

* return err if jwt parsing fails

* set global check to true when accessing user apis

* set netid for acls api calls

* set netid for acls api calls

* update role and groups routes

* add validation checks

* add invite flow apis and magic links

* add invited user via oauth signup automatically

* create invited user on oauth signup, with groups in the invite

* add group validation for user invite

* update create user handler with new role mgmt

* add validation checks

* create user invites tables

* add error logging for email invite

* fix invite singup url

* debug log

* get query params from url

* get query params from url

* add query escape

* debug log

* debug log

* fix user signup via invite api

* set admin field for backward compatbility

* use new role id for user apis

* deprecate use of old admin fields

* deprecate usage of old user fields

* add user role as service user if empty

* setup email sender

* delete invite after user singup

* add plaform user role

* redirect on invite verification link

* fix invite redirect

* temporary redirect

* fix invite redirect

* point invite link to frontend

* fix query params lookup

* add resend support, configure email interface types

* fix groups and user creation

* validate user groups, add check for metrics api in middleware

* add invite url to invite model

* migrate rac apis to new user mgmt

* handle network nodes

* add platform user to default role

* fix user role migration

* add default on rag creation and cleanup after deletion

* fix rac apis

* change to invite code param

* filter nodes and hosts based on user network access

* extend create user group req to accomodate users

* filter network based on user access

* format oauth error

* move user roles and groups

* fix get user v1 api

* move user mgmt func to pro

* add user auth type to user model

* fix roles init

* remove platform role from group object

* list only platform roles

* add network roles to invite req

* create default groups and roles

* fix middleware for global access

* create default role

* fix nodes filter with global network roles

* block selfupdate of groups and network roles

* delete netID if net roles are empty

* validate user roles nd groups on update

* set extclient permission scope when rag vpn access is set

* allow deletion of roles and groups

* replace _ with - in role naming convention

* fix failover middleware mgmt

* format oauth templates

* fetch route temaplate

* return err if user wrong login type

* check user groups on rac apis

* fix rac apis

* fix resp msg

* add validation checks for admin invite

* return oauth type

* format group err msg

* fix html tag

* clean up default groups

* create default rag role

* add UI name to roles

* remove default net group from user when deleted

* reorder migration funcs

* fix duplicacy of hosts

* check old field for migration

* from pro to ce make all secondary users admins

* from pro to ce make all secondary users admins

* revert: from pro to ce make all secondary users admins

* make sure downgrades work

* fix pending users approval

* fix duplicate hosts

* fix duplicate hosts entries

* fix cache reference issue

* feat: configure FRONTEND_URL during installation

* disable user vpn access when network roles are modified

* rm vpn acces when roles or groups are deleted

* add http to frontend url

* revert crypto version

* downgrade crytpo version

* add platform id check on user invites

---------

Co-authored-by: the_aceix <aceixsmartx@gmail.com>
2024-08-20 17:08:56 +05:30

159 lines
4.8 KiB
Go

package auth
import (
"bytes"
"fmt"
"net/http"
"time"
"github.com/gorilla/mux"
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/logic/pro/netcache"
"github.com/gravitl/netmaker/models"
)
var (
redirectUrl string
)
// HandleHostSSOCallback handles the callback from the sso endpoint
// It is the analogue of auth.handleNodeSSOCallback but takes care of the end point flow
// Retrieves the mkey from the state cache and adds the machine to the users email namespace
// TODO: A confirmation page for new machines should be added to avoid phishing vulnerabilities
// TODO: Add groups information from OIDC tokens into machine HostInfo
// Listens in /oidc/callback.
func HandleHostSSOCallback(w http.ResponseWriter, r *http.Request) {
var functions = getCurrentAuthFunctions()
if functions == nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("bad conf"))
logger.Log(0, "Missing Oauth config in HandleNodeSSOCallback")
return
}
state, code := getStateAndCode(r)
var userClaims, err = functions[get_user_info].(func(string, string) (*OAuthUser, error))(state, code)
if err != nil {
logger.Log(0, "error when getting user info from callback:", err.Error())
handleOauthNotConfigured(w)
return
}
if code == "" || state == "" {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("Wrong params"))
logger.Log(0, "Missing params in HandleSSOCallback")
return
}
// all responses should be in html format from here on out
w.Header().Add("content-type", "text/html; charset=utf-8")
// retrieve machinekey from state cache
reqKeyIf, machineKeyFoundErr := netcache.Get(state)
if machineKeyFoundErr != nil {
logger.Log(0, "requested machine state key expired before authorisation completed -", machineKeyFoundErr.Error())
reqKeyIf = &netcache.CValue{
Network: "invalid",
Value: state,
Pass: "",
User: "netmaker",
Expiration: time.Now(),
}
response := returnErrTemplate("", "requested machine state key expired before authorisation completed", state, reqKeyIf)
w.WriteHeader(http.StatusInternalServerError)
w.Write(response)
return
}
// check if user exists
user, err := logic.GetUser(userClaims.getUserName())
if err != nil {
handleOauthUserNotFound(w)
return
}
if user.PlatformRoleID != models.AdminRole && user.PlatformRoleID != models.SuperAdminRole {
response := returnErrTemplate(userClaims.getUserName(), "only admin users can register using SSO", state, reqKeyIf)
w.WriteHeader(http.StatusForbidden)
w.Write(response)
return
}
logger.Log(1, "registering host for user:", userClaims.getUserName(), reqKeyIf.Host.Name, reqKeyIf.Host.ID.String())
// Send OK to user in the browser
var response bytes.Buffer
if err := ssoCallbackTemplate.Execute(&response, ssoCallbackTemplateConfig{
User: userClaims.getUserName(),
Verb: "Authenticated",
}); err != nil {
logger.Log(0, "Could not render SSO callback template ", err.Error())
response := returnErrTemplate(reqKeyIf.User, "Could not render SSO callback template", state, reqKeyIf)
w.WriteHeader(http.StatusInternalServerError)
w.Write(response)
} else {
w.WriteHeader(http.StatusOK)
w.Write(response.Bytes())
}
reqKeyIf.User = userClaims.getUserName() // set the cached registering hosts' user
if err = netcache.Set(state, reqKeyIf); err != nil {
logger.Log(0, "machine failed to complete join on network,", reqKeyIf.Network, "-", err.Error())
return
}
}
func setNetcache(ncache *netcache.CValue, state string) error {
if ncache == nil {
return fmt.Errorf("cache miss")
}
var err error
if err = netcache.Set(state, ncache); err != nil {
logger.Log(0, "machine failed to complete join on network,", ncache.Network, "-", err.Error())
}
return err
}
func returnErrTemplate(uname, message, state string, ncache *netcache.CValue) []byte {
var response bytes.Buffer
if ncache != nil {
ncache.Pass = message
}
err := ssoErrCallbackTemplate.Execute(&response, ssoCallbackTemplateConfig{
User: uname,
Verb: message,
})
if err != nil {
return []byte(err.Error())
}
err = setNetcache(ncache, state)
if err != nil {
return []byte(err.Error())
}
return response.Bytes()
}
// RegisterHostSSO redirects to the IDP for authentication
// Puts machine key in cache so the callback can retrieve it using the oidc state param
// Listens in /oidc/register/:regKey.
func RegisterHostSSO(w http.ResponseWriter, r *http.Request) {
if auth_provider == nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("invalid login attempt"))
return
}
vars := mux.Vars(r)
// machineKeyStr this is not key but state
machineKeyStr := vars["regKey"]
if machineKeyStr == "" {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("invalid login attempt"))
return
}
http.Redirect(w, r, auth_provider.AuthCodeURL(machineKeyStr), http.StatusSeeOther)
}