Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions internal/app/contracts/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,22 @@ type InitializeNewUserFHIRResourcesOutput struct {
PersonID string
}

// LookupUserFHIRResourceIDsInput defines the input for looking up existing FHIR resource IDs.
// This is a read-only operation that only queries existing resources, unlike InitializeNewUserFHIRResources
// which creates resources if they don't exist.
type LookupUserFHIRResourceIDsInput struct {
SuperTokenUserID string
}

type UserUsecase interface {
GetUserProfileBySession(ctx context.Context, sessionData string) (*responses.UserProfile, error)
UpdateUserProfileBySession(ctx context.Context, sessionData string, request *requests.UpdateProfile) (*responses.UpdateUserProfile, error)
DeleteUserBySession(ctx context.Context, sessionData string) error
DeactivateUserBySession(ctx context.Context, sessionData string) error
InitializeNewUserFHIRResources(ctx context.Context, input *InitializeNewUserFHIRResourcesInput) (*InitializeNewUserFHIRResourcesOutput, error)
// LookupUserFHIRResourceIDs queries existing FHIR resources by SuperTokenUserID.
// Unlike InitializeNewUserFHIRResources, this is read-only and will not create any resources.
LookupUserFHIRResourceIDs(ctx context.Context, input *LookupUserFHIRResourceIDsInput) (*InitializeNewUserFHIRResourcesOutput, error)
}

type UserRepository interface {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ func (ctrl *WebhookController) HandleEnqueueWebHook(w http.ResponseWriter, r *ht
actorID = "api-key-superadmin"
}
}
if uid, ok := r.Context().Value("uid").(string); ok && uid != "" && !strings.EqualFold(uid, "anonymous") {
if uid, ok := r.Context().Value(constvars.CONTEXT_UID).(string); ok && uid != "" && !strings.EqualFold(uid, "anonymous") {
actorID = uid
}

Expand Down
99 changes: 56 additions & 43 deletions internal/app/delivery/http/middlewares/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,17 @@ import (
)

// Deprecated: all context keys must use typed string, such as constvars.ContextKey
type ContextKey string

const (
keyFHIRRole = "fhirRole"
keyFHIRID = "fhirID"
keyRoles = "roles"
keyUID = "uid"
supertokenAccessTokenPayloadRolesKey = "st-role"
supertokenAccessTokenPayloadRolesValueKey = "v"
keyFHIRRole ContextKey = "fhirRole"
keyFHIRID ContextKey = "fhirID"
keyFHIRResourceId ContextKey = "fhirResourceId"
keyRoles ContextKey = "roles"
keyUID ContextKey = "uid"
supertokenAccessTokenPayloadRolesKey = "st-role"
supertokenAccessTokenPayloadRolesValueKey = "v"
supertokenAccessTokenPayloadFhirResourceId = "fhirResourceId"
)

func (m *Middlewares) SessionOptional(next http.Handler) http.Handler {
Expand All @@ -28,51 +32,60 @@ func (m *Middlewares) SessionOptional(next http.Handler) http.Handler {
return
}

sessRequired := false
sess, _ := session.GetSession(r, w, &sessmodels.VerifySessionOptions{SessionRequired: &sessRequired})

roles := []string{constvars.KonsulinRoleGuest}
uid := ""

if sess != nil {
uid = sess.GetUserID()
if raw := sess.GetAccessTokenPayload(); raw != nil {
if rolesData, exists := raw[supertokenAccessTokenPayloadRolesKey]; exists {
if rolesMap, ok := rolesData.(map[string]interface{}); ok {
if rolesValue, ok := rolesMap[supertokenAccessTokenPayloadRolesValueKey]; ok {
if rolesList, ok := rolesValue.([]interface{}); ok {

roles = []string{}
for _, item := range rolesList {
if role, ok := item.(string); ok {
roles = append(roles, role)
}
sessRequired := false
sess, _ := session.GetSession(r, w, &sessmodels.VerifySessionOptions{SessionRequired: &sessRequired})

roles := []string{constvars.KonsulinRoleGuest}
uid := ""
fhirResourceId := ""

if sess != nil {
uid = sess.GetUserID()
if raw := sess.GetAccessTokenPayload(); raw != nil {
if rolesData, exists := raw[supertokenAccessTokenPayloadRolesKey]; exists {
if rolesMap, ok := rolesData.(map[string]interface{}); ok {
if rolesValue, ok := rolesMap[supertokenAccessTokenPayloadRolesValueKey]; ok {
if rolesList, ok := rolesValue.([]interface{}); ok {

roles = []string{}
for _, item := range rolesList {
if role, ok := item.(string); ok {
roles = append(roles, role)
}
}
}
}
}
}
} else {

uid = "anonymous"
roles = []string{constvars.KonsulinRoleGuest}

m.Log.Info("Anonymous session created",
zap.String("ip", r.RemoteAddr),
zap.String("user_agent", r.UserAgent()),
zap.String("endpoint", r.URL.Path),
zap.String("method", r.Method),
)
// Read fhirResourceId from access token payload
if fhirResId, exists := raw[supertokenAccessTokenPayloadFhirResourceId]; exists {
if resId, ok := fhirResId.(string); ok {
fhirResourceId = resId
}
}
}

ctx := context.WithValue(r.Context(), keyRoles, roles)
ctx = context.WithValue(ctx, keyUID, uid)

// new keys for context will be used for now and one and this
// will deprecate the use of untyped string in context keys
ctx = context.WithValue(ctx, constvars.CONTEXT_FHIR_ROLE, roles)
ctx = context.WithValue(ctx, constvars.CONTEXT_UID, uid)
} else {

uid = "anonymous"
roles = []string{constvars.KonsulinRoleGuest}

m.Log.Info("Anonymous session created",
zap.String("ip", r.RemoteAddr),
zap.String("user_agent", r.UserAgent()),
zap.String("endpoint", r.URL.Path),
zap.String("method", r.Method),
)
}

ctx := context.WithValue(r.Context(), keyRoles, roles)
ctx = context.WithValue(ctx, keyUID, uid)
ctx = context.WithValue(ctx, keyFHIRResourceId, fhirResourceId)

// Typed context keys (constvars.ContextKey) - these will replace the deprecated local ContextKey keys above.
ctx = context.WithValue(ctx, constvars.CONTEXT_FHIR_ROLE, roles)
ctx = context.WithValue(ctx, constvars.CONTEXT_UID, uid)
ctx = context.WithValue(ctx, constvars.CONTEXT_FHIR_RESOURCE_ID, fhirResourceId)

next.ServeHTTP(w, r.WithContext(ctx))
})
Expand Down
4 changes: 2 additions & 2 deletions internal/app/delivery/http/routers/auth_router_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,12 +276,12 @@ func TestAuthRouter_ContextPropagation(t *testing.T) {
return false
}

roles, ok := ctx.Value("roles").([]string)
roles, ok := ctx.Value(constvars.CONTEXT_FHIR_ROLE).([]string)
if !ok || len(roles) != 1 || roles[0] != constvars.KonsulinRoleSuperadmin {
return false
}

uid, ok := ctx.Value("uid").(string)
uid, ok := ctx.Value(constvars.CONTEXT_UID).(string)
if !ok || uid != "api-key-superadmin" {
return false
}
Expand Down
Loading
Loading