fix(security): address validation review comments - mutex safety and issuer normalization

Agent-Logs-Url: https://github.com/bitechdev/ResolveSpec/sessions/e886b781-c910-425f-aa6f-06d13c46dcc7

Co-authored-by: warkanum <208308+warkanum@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-04-09 14:07:45 +00:00
committed by GitHub
parent 850ad2b2ab
commit ca0545e144
2 changed files with 20 additions and 6 deletions

View File

@@ -1545,6 +1545,8 @@ BEGIN
'username', u.username, 'username', u.username,
'email', u.email, 'email', u.email,
'user_level', u.user_level, 'user_level', u.user_level,
-- NULLIF converts empty string to NULL; string_to_array(NULL) returns NULL;
-- to_jsonb(NULL) returns NULL; COALESCE then returns '[]' for NULL/empty roles.
'roles', COALESCE(to_jsonb(string_to_array(NULLIF(u.roles, ''), ',')), '[]'::jsonb), 'roles', COALESCE(to_jsonb(string_to_array(NULLIF(u.roles, ''), ',')), '[]'::jsonb),
'exp', EXTRACT(EPOCH FROM s.expires_at)::bigint, 'exp', EXTRACT(EPOCH FROM s.expires_at)::bigint,
'iat', EXTRACT(EPOCH FROM s.created_at)::bigint 'iat', EXTRACT(EPOCH FROM s.created_at)::bigint

View File

@@ -128,8 +128,8 @@ func NewOAuthServer(cfg OAuthServerConfig, auth *DatabaseAuthenticator) *OAuthSe
if cfg.AuthCodeTTL == 0 { if cfg.AuthCodeTTL == 0 {
cfg.AuthCodeTTL = 2 * time.Minute cfg.AuthCodeTTL = 2 * time.Minute
} }
// Normalize issuer: trim trailing slash to ensure consistent endpoint URL construction. // Normalize issuer: remove trailing slash to ensure consistent endpoint URL construction.
cfg.Issuer = strings.TrimRight(cfg.Issuer, "/") cfg.Issuer = strings.TrimSuffix(cfg.Issuer, "/")
s := &OAuthServer{ s := &OAuthServer{
cfg: cfg, cfg: cfg,
auth: auth, auth: auth,
@@ -704,9 +704,17 @@ func (s *OAuthServer) revokeHandler(w http.ResponseWriter, r *http.Request) {
if s.auth != nil { if s.auth != nil {
s.auth.OAuthRevokeToken(r.Context(), token) //nolint:errcheck s.auth.OAuthRevokeToken(r.Context(), token) //nolint:errcheck
} else if len(s.providers) > 0 { } else {
// In external-provider-only mode, attempt revocation via the first provider's auth. // In external-provider-only mode, attempt revocation via the first provider's auth.
s.providers[0].auth.OAuthRevokeToken(r.Context(), token) //nolint:errcheck s.mu.RLock()
var providerAuth *DatabaseAuthenticator
if len(s.providers) > 0 {
providerAuth = s.providers[0].auth
}
s.mu.RUnlock()
if providerAuth != nil {
providerAuth.OAuthRevokeToken(r.Context(), token) //nolint:errcheck
}
} }
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
} }
@@ -735,8 +743,12 @@ func (s *OAuthServer) introspectHandler(w http.ResponseWriter, r *http.Request)
// Resolve the authenticator to use: prefer the primary auth, then the first provider's auth. // Resolve the authenticator to use: prefer the primary auth, then the first provider's auth.
authToUse := s.auth authToUse := s.auth
if authToUse == nil && len(s.providers) > 0 { if authToUse == nil {
authToUse = s.providers[0].auth s.mu.RLock()
if len(s.providers) > 0 {
authToUse = s.providers[0].auth
}
s.mu.RUnlock()
} }
if authToUse == nil { if authToUse == nil {
w.Write([]byte(`{"active":false}`)) //nolint:errcheck w.Write([]byte(`{"active":false}`)) //nolint:errcheck