Files
oci-portal/internal/api/federation.go
T
Wang Defa dbba1f4905
CI / test (push) Successful in 30s
Release / release (push) Successful in 49s
发布 0.1.0:通知渠道、告警规则、令牌版本与安全加固
2026-07-10 17:38:34 +08:00

236 lines
7.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package api
import (
"net/http"
"github.com/gin-gonic/gin"
"oci-portal/internal/oci"
)
// ---- FederationSAML IdP 与 sign-on 免 MFA ----
// createIdpRequest 的映射 / JIT 字段全部可缺省:布尔用指针区分「未传」,
// 缺省即控制台默认(JIT 开启建用户不更新、分配 Administrators 组、
// 名称 ID 格式无、NameID 映射用户名)。
type createIdpRequest struct {
Name string `json:"name" binding:"required"`
Metadata string `json:"metadata" binding:"required"`
Description string `json:"description"`
IconURL string `json:"iconUrl"`
NameIDFormat string `json:"nameIdFormat"`
AssertionAttribute string `json:"assertionAttribute"`
UserStoreAttribute string `json:"userStoreAttribute"`
JitEnabled *bool `json:"jitEnabled"`
JitCreate *bool `json:"jitCreate"`
JitUpdate *bool `json:"jitUpdate"`
JitAssignAdminGroup *bool `json:"jitAssignAdminGroup"`
JitMapEmail bool `json:"jitMapEmail"`
}
func boolOr(v *bool, def bool) bool {
if v == nil {
return def
}
return *v
}
// @Summary 身份提供商列表
// @Tags 租户 IAM
// @Param id path int true "配置 ID"
// @Param domainId query string false "身份域 OCID(缺省 Default 域)"
// @Success 200 {object} map[string]any
// @Security BearerAuth
// @Router /api/v1/oci-configs/{id}/identity-providers [get]
func (h *ociConfigHandler) listIdentityProviders(c *gin.Context) {
id, ok := pathID(c)
if !ok {
return
}
idps, err := h.svc.IdentityProviders(c.Request.Context(), id, c.Query("domainId"))
if err != nil {
respondError(c, err)
return
}
c.JSON(http.StatusOK, idps)
}
// @Summary 创建身份提供商(SAML)
// @Tags 租户 IAM
// @Param id path int true "配置 ID"
// @Param domainId query string false "身份域 OCID(缺省 Default 域)"
// @Param body body createIdpRequest true "请求体"
// @Success 201 {object} map[string]any
// @Security BearerAuth
// @Router /api/v1/oci-configs/{id}/identity-providers [post]
func (h *ociConfigHandler) createIdentityProvider(c *gin.Context) {
id, ok := pathID(c)
if !ok {
return
}
var req createIdpRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
idp, err := h.svc.CreateIdentityProvider(c.Request.Context(), id, c.Query("domainId"), oci.CreateIdpInput{
Name: req.Name,
Metadata: req.Metadata,
Description: req.Description,
IconURL: req.IconURL,
NameIDFormat: req.NameIDFormat,
AssertionAttribute: req.AssertionAttribute,
UserStoreAttribute: req.UserStoreAttribute,
JitEnabled: boolOr(req.JitEnabled, true),
JitCreate: boolOr(req.JitCreate, true),
JitUpdate: boolOr(req.JitUpdate, false),
JitAssignAdminGroup: boolOr(req.JitAssignAdminGroup, true),
JitMapEmail: req.JitMapEmail,
})
if err != nil {
respondError(c, err)
return
}
c.JSON(http.StatusCreated, idp)
}
// @Summary 激活身份提供商
// @Tags 租户 IAM
// @Param id path int true "配置 ID"
// @Param domainId query string false "身份域 OCID(缺省 Default 域)"
// @Param idpId path string true "idpId"
// @Param body body object true "请求体(见接口说明)"
// @Success 200 {object} map[string]any
// @Security BearerAuth
// @Router /api/v1/oci-configs/{id}/identity-providers/{idpId}/activate [post]
func (h *ociConfigHandler) activateIdentityProvider(c *gin.Context) {
id, ok := pathID(c)
if !ok {
return
}
var req struct {
Enabled *bool `json:"enabled" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
idp, err := h.svc.SetIdentityProviderEnabled(c.Request.Context(), id, c.Query("domainId"), c.Param("idpId"), *req.Enabled)
if err != nil {
respondError(c, err)
return
}
c.JSON(http.StatusOK, idp)
}
// @Summary 删除身份提供商
// @Tags 租户 IAM
// @Param id path int true "配置 ID"
// @Param domainId query string false "身份域 OCID(缺省 Default 域)"
// @Param idpId path string true "idpId"
// @Success 204 "无内容"
// @Security BearerAuth
// @Router /api/v1/oci-configs/{id}/identity-providers/{idpId} [delete]
func (h *ociConfigHandler) deleteIdentityProvider(c *gin.Context) {
id, ok := pathID(c)
if !ok {
return
}
if err := h.svc.DeleteIdentityProvider(c.Request.Context(), id, c.Query("domainId"), c.Param("idpId")); err != nil {
respondError(c, err)
return
}
c.Status(http.StatusNoContent)
}
// @Summary 下载 SAML 元数据
// @Tags 租户 IAM
// @Param id path int true "配置 ID"
// @Param domainId query string false "身份域 OCID(缺省 Default 域)"
// @Success 200 {object} map[string]any
// @Security BearerAuth
// @Router /api/v1/oci-configs/{id}/saml-metadata [get]
func (h *ociConfigHandler) downloadSamlMetadata(c *gin.Context) {
id, ok := pathID(c)
if !ok {
return
}
metadata, err := h.svc.DomainSamlMetadata(c.Request.Context(), id, c.Query("domainId"))
if err != nil {
respondError(c, err)
return
}
c.Header("Content-Disposition", `attachment; filename="oci-domain-saml-metadata.xml"`)
c.Data(http.StatusOK, "application/xml", metadata)
}
// @Summary 单点登录规则列表
// @Tags 租户 IAM
// @Param id path int true "配置 ID"
// @Param domainId query string false "身份域 OCID(缺省 Default 域)"
// @Success 200 {object} map[string]any
// @Security BearerAuth
// @Router /api/v1/oci-configs/{id}/sign-on-rules [get]
func (h *ociConfigHandler) listSignOnRules(c *gin.Context) {
id, ok := pathID(c)
if !ok {
return
}
rules, err := h.svc.ConsoleSignOnRules(c.Request.Context(), id, c.Query("domainId"))
if err != nil {
respondError(c, err)
return
}
c.JSON(http.StatusOK, rules)
}
// @Summary 创建 MFA 豁免规则
// @Tags 租户 IAM
// @Param id path int true "配置 ID"
// @Param domainId query string false "身份域 OCID(缺省 Default 域)"
// @Param body body object true "请求体(见接口说明)"
// @Success 201 {object} map[string]any
// @Security BearerAuth
// @Router /api/v1/oci-configs/{id}/sign-on-exemptions [post]
func (h *ociConfigHandler) createMfaExemption(c *gin.Context) {
id, ok := pathID(c)
if !ok {
return
}
var req struct {
IdentityProviderID string `json:"identityProviderId" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
rule, err := h.svc.CreateMfaExemption(c.Request.Context(), id, c.Query("domainId"), req.IdentityProviderID)
if err != nil {
respondError(c, err)
return
}
c.JSON(http.StatusCreated, rule)
}
// @Summary 删除 MFA 豁免规则
// @Tags 租户 IAM
// @Param id path int true "配置 ID"
// @Param domainId query string false "身份域 OCID(缺省 Default 域)"
// @Param ruleId path string true "ruleId"
// @Success 204 "无内容"
// @Security BearerAuth
// @Router /api/v1/oci-configs/{id}/sign-on-exemptions/{ruleId} [delete]
func (h *ociConfigHandler) deleteMfaExemption(c *gin.Context) {
id, ok := pathID(c)
if !ok {
return
}
if err := h.svc.DeleteMfaExemption(c.Request.Context(), id, c.Query("domainId"), c.Param("ruleId")); err != nil {
respondError(c, err)
return
}
c.Status(http.StatusNoContent)
}