forked from baron/baron-sso
일반 사용자의 DevFront 접근 및 RP 관리자 권한 연동
This commit is contained in:
@@ -199,6 +199,7 @@ var allowedRelyingPartyOperatorRelations = map[string]struct{}{
|
||||
"admins": {},
|
||||
"creator": {},
|
||||
"config_editor": {},
|
||||
"secret_viewer": {},
|
||||
"secret_rotator": {},
|
||||
"jwks_viewer": {},
|
||||
"jwks_operator": {},
|
||||
@@ -215,7 +216,7 @@ func normalizeUserRole(role string) string {
|
||||
|
||||
func isDevConsoleRoleAllowed(role string) bool {
|
||||
switch normalizeUserRole(role) {
|
||||
case domain.RoleSuperAdmin, domain.RoleTenantAdmin, domain.RoleRPAdmin:
|
||||
case domain.RoleSuperAdmin, domain.RoleTenantAdmin, domain.RoleRPAdmin, domain.RoleUser:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
@@ -372,6 +373,32 @@ func (h *DevHandler) canOperateClientByPermit(c *fiber.Ctx, profile *domain.User
|
||||
return err == nil && allowed
|
||||
}
|
||||
|
||||
func (h *DevHandler) canViewClientSecret(c *fiber.Ctx, profile *domain.UserProfileResponse, summary clientSummary) bool {
|
||||
if canAccessClientByLegacyScope(profile, summary) {
|
||||
return true
|
||||
}
|
||||
return h.canOperateClientByPermit(c, profile, summary, "view_secret")
|
||||
}
|
||||
|
||||
func (h *DevHandler) canBypassPrivateClientRestriction(c *fiber.Ctx, profile *domain.UserProfileResponse, summary clientSummary, relation string) bool {
|
||||
if h.canOperateClientByPermit(c, profile, summary, relation) {
|
||||
return true
|
||||
}
|
||||
allowed, err := h.checkAppManagerPermission(c)
|
||||
return err == nil && allowed
|
||||
}
|
||||
|
||||
func (h *DevHandler) redactClientSecretUnlessAllowed(c *fiber.Ctx, profile *domain.UserProfileResponse, summary clientSummary) clientSummary {
|
||||
if summary.ClientSecret == "" {
|
||||
return summary
|
||||
}
|
||||
if h.canViewClientSecret(c, profile, summary) {
|
||||
return summary
|
||||
}
|
||||
summary.ClientSecret = ""
|
||||
return summary
|
||||
}
|
||||
|
||||
func (h *DevHandler) canViewClientRelations(c *fiber.Ctx, profile *domain.UserProfileResponse, summary clientSummary) bool {
|
||||
if h.canOperateClientByPermit(c, profile, summary, "view_relationships") {
|
||||
return true
|
||||
@@ -474,7 +501,11 @@ func resolveClientTenantID(summary clientSummary) string {
|
||||
}
|
||||
|
||||
func isRPAdminClientAllowed(profile *domain.UserProfileResponse, clientID string) bool {
|
||||
if normalizeUserRole(profileRole(profile)) != domain.RoleRPAdmin {
|
||||
role := normalizeUserRole(profileRole(profile))
|
||||
if role == domain.RoleUser {
|
||||
return false
|
||||
}
|
||||
if role != domain.RoleRPAdmin {
|
||||
return true
|
||||
}
|
||||
allowed := managedClientIDsFromProfile(profile)
|
||||
@@ -665,7 +696,11 @@ func (h *DevHandler) SearchUsers(c *fiber.Ctx) error {
|
||||
return errorJSON(c, fiber.StatusUnauthorized, "unauthorized: authentication required")
|
||||
}
|
||||
if !isDevConsoleRoleAllowed(normalizeUserRole(profile.Role)) {
|
||||
return errorJSON(c, fiber.StatusForbidden, "forbidden")
|
||||
clientID := strings.TrimSpace(c.Query("clientId"))
|
||||
summary, err := h.loadClientSummary(c.Context(), clientID)
|
||||
if clientID == "" || err != nil || !h.canManageClientRelations(c, profile, summary) {
|
||||
return errorJSON(c, fiber.StatusForbidden, "forbidden")
|
||||
}
|
||||
}
|
||||
if h.KratosAdmin == nil {
|
||||
return errorJSON(c, fiber.StatusServiceUnavailable, "kratos admin unavailable")
|
||||
@@ -993,7 +1028,7 @@ func (h *DevHandler) ListClients(c *fiber.Ctx) error {
|
||||
return errorJSON(c, fiber.StatusUnauthorized, "unauthorized: authentication required")
|
||||
}
|
||||
role := normalizeUserRole(profile.Role)
|
||||
if !isDevConsoleViewerRole(role) {
|
||||
if !isDevConsoleRoleAllowed(role) {
|
||||
return errorJSON(c, fiber.StatusForbidden, "forbidden")
|
||||
}
|
||||
|
||||
@@ -1054,7 +1089,7 @@ func (h *DevHandler) ListClients(c *fiber.Ctx) error {
|
||||
continue
|
||||
}
|
||||
|
||||
items = append(items, summary)
|
||||
items = append(items, h.redactClientSecretUnlessAllowed(c, profile, summary))
|
||||
}
|
||||
|
||||
return c.JSON(clientListResponse{
|
||||
@@ -1240,6 +1275,7 @@ func (h *DevHandler) GetClient(c *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
cacheState, _ := h.publicHeadlessJWKSCacheState(summary.ID)
|
||||
summary = h.redactClientSecretUnlessAllowed(c, profile, summary)
|
||||
|
||||
return c.JSON(clientDetailResponse{
|
||||
Client: summary,
|
||||
@@ -1318,17 +1354,17 @@ func (h *DevHandler) UpdateClientStatus(c *fiber.Ctx) error {
|
||||
return errorJSON(c, fiber.StatusUnauthorized, "unauthorized: authentication required")
|
||||
}
|
||||
role := normalizeUserRole(profile.Role)
|
||||
if !isDevConsoleRoleAllowed(role) {
|
||||
if !isDevConsoleViewerRole(role) {
|
||||
return errorJSON(c, fiber.StatusForbidden, "forbidden")
|
||||
}
|
||||
|
||||
if !canAccessClientByLegacyScope(profile, summary) && !h.canOperateClientByPermit(c, profile, summary, "change_status") {
|
||||
canChangeStatusByPermit := h.canOperateClientByPermit(c, profile, summary, "change_status")
|
||||
if !canAccessClientByLegacyScope(profile, summary) && !canChangeStatusByPermit {
|
||||
return errorJSON(c, fiber.StatusForbidden, "forbidden: rp_admin scope does not include this client")
|
||||
}
|
||||
|
||||
if summary.Type == "private" {
|
||||
isAppManager, _ := h.checkAppManagerPermission(c)
|
||||
if !isAppManager {
|
||||
if summary.Type == "private" && !h.canBypassPrivateClientRestriction(c, profile, summary, "change_status") {
|
||||
if !canChangeStatusByPermit {
|
||||
return errorJSON(c, fiber.StatusForbidden, "forbidden: insufficient permissions for private client")
|
||||
}
|
||||
}
|
||||
@@ -1352,6 +1388,7 @@ func (h *DevHandler) UpdateClientStatus(c *fiber.Ctx) error {
|
||||
}
|
||||
|
||||
updatedSummary := h.mapClientSummary(*updated)
|
||||
updatedSummary = h.redactClientSecretUnlessAllowed(c, profile, updatedSummary)
|
||||
cacheState, _ := h.publicHeadlessJWKSCacheState(updatedSummary.ID)
|
||||
return c.JSON(clientDetailResponse{
|
||||
Client: updatedSummary,
|
||||
@@ -1566,7 +1603,7 @@ func (h *DevHandler) UpdateClient(c *fiber.Ctx) error {
|
||||
return errorJSON(c, fiber.StatusUnauthorized, "unauthorized: authentication required")
|
||||
}
|
||||
role := normalizeUserRole(profile.Role)
|
||||
if !isDevConsoleRoleAllowed(role) {
|
||||
if !isDevConsoleViewerRole(role) {
|
||||
return errorJSON(c, fiber.StatusForbidden, "forbidden")
|
||||
}
|
||||
|
||||
@@ -1584,11 +1621,7 @@ func (h *DevHandler) UpdateClient(c *fiber.Ctx) error {
|
||||
|
||||
// [Security] Check permission for private clients (both current and new type)
|
||||
if currentSummary.Type == "private" || clientType == "private" {
|
||||
isAppManager, err := h.checkAppManagerPermission(c)
|
||||
if err != nil {
|
||||
return errorJSON(c, fiber.StatusInternalServerError, "permission check error")
|
||||
}
|
||||
if !isAppManager {
|
||||
if !h.canBypassPrivateClientRestriction(c, profile, currentSummary, "edit_config") {
|
||||
return errorJSON(c, fiber.StatusForbidden, "forbidden: insufficient permissions for private client")
|
||||
}
|
||||
}
|
||||
@@ -1736,7 +1769,7 @@ func (h *DevHandler) DeleteClient(c *fiber.Ctx) error {
|
||||
return errorJSON(c, fiber.StatusUnauthorized, "unauthorized: authentication required")
|
||||
}
|
||||
role := normalizeUserRole(profile.Role)
|
||||
if !isDevConsoleRoleAllowed(role) {
|
||||
if !isDevConsoleViewerRole(role) {
|
||||
return errorJSON(c, fiber.StatusForbidden, "forbidden")
|
||||
}
|
||||
|
||||
@@ -1746,8 +1779,7 @@ func (h *DevHandler) DeleteClient(c *fiber.Ctx) error {
|
||||
|
||||
// [Security] Check permission for private clients
|
||||
if summary.Type == "private" {
|
||||
isAppManager, _ := h.checkAppManagerPermission(c)
|
||||
if !isAppManager {
|
||||
if !h.canBypassPrivateClientRestriction(c, profile, summary, "manage") {
|
||||
return errorJSON(c, fiber.StatusForbidden, "forbidden: insufficient permissions for private client")
|
||||
}
|
||||
}
|
||||
@@ -1986,7 +2018,7 @@ func (h *DevHandler) RotateClientSecret(c *fiber.Ctx) error {
|
||||
return errorJSON(c, fiber.StatusUnauthorized, "unauthorized: authentication required")
|
||||
}
|
||||
role := normalizeUserRole(profile.Role)
|
||||
if !isDevConsoleRoleAllowed(role) {
|
||||
if !isDevConsoleViewerRole(role) {
|
||||
return errorJSON(c, fiber.StatusForbidden, "forbidden")
|
||||
}
|
||||
|
||||
@@ -1997,8 +2029,7 @@ func (h *DevHandler) RotateClientSecret(c *fiber.Ctx) error {
|
||||
|
||||
// [Security] Check permission for private clients
|
||||
if summary.Type == "private" {
|
||||
isAppManager, _ := h.checkAppManagerPermission(c)
|
||||
if !isAppManager {
|
||||
if !h.canBypassPrivateClientRestriction(c, profile, summary, "rotate_secret") {
|
||||
return errorJSON(c, fiber.StatusForbidden, "forbidden: insufficient permissions for private client")
|
||||
}
|
||||
}
|
||||
@@ -2076,7 +2107,7 @@ func (h *DevHandler) RefreshHeadlessJWKSCache(c *fiber.Ctx) error {
|
||||
return errorJSON(c, fiber.StatusUnauthorized, "unauthorized: authentication required")
|
||||
}
|
||||
role := normalizeUserRole(profile.Role)
|
||||
if !isDevConsoleRoleAllowed(role) {
|
||||
if !isDevConsoleViewerRole(role) {
|
||||
return errorJSON(c, fiber.StatusForbidden, "forbidden")
|
||||
}
|
||||
if !canAccessClientByLegacyScope(profile, summary) && !h.canOperateClientByPermit(c, profile, summary, "operate_jwks") {
|
||||
@@ -2141,18 +2172,10 @@ func (h *DevHandler) RevokeHeadlessJWKSCache(c *fiber.Ctx) error {
|
||||
return errorJSON(c, fiber.StatusUnauthorized, "unauthorized: authentication required")
|
||||
}
|
||||
role := normalizeUserRole(profile.Role)
|
||||
if !isDevConsoleRoleAllowed(role) {
|
||||
if !isDevConsoleViewerRole(role) {
|
||||
return errorJSON(c, fiber.StatusForbidden, "forbidden")
|
||||
}
|
||||
isSuperAdmin := role == domain.RoleSuperAdmin
|
||||
userTenantID := tenantIDFromProfile(profile)
|
||||
if !isSuperAdmin {
|
||||
clientTenantID := resolveClientTenantID(summary)
|
||||
if clientTenantID != userTenantID {
|
||||
return errorJSON(c, fiber.StatusForbidden, "forbidden: access denied to client in another tenant")
|
||||
}
|
||||
}
|
||||
if !isRPAdminClientAllowed(profile, summary.ID) {
|
||||
if !canAccessClientByLegacyScope(profile, summary) && !h.canOperateClientByPermit(c, profile, summary, "operate_jwks") {
|
||||
return errorJSON(c, fiber.StatusForbidden, "forbidden: rp_admin scope does not include this client")
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user