236 lines
7.3 KiB
Go
236 lines
7.3 KiB
Go
package api
|
||
|
||
import (
|
||
"net/http"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
|
||
"oci-portal/internal/oci"
|
||
)
|
||
|
||
// ---- Federation:SAML 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)
|
||
}
|