Skip to content
Merged
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
2 changes: 1 addition & 1 deletion core/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func InitializeRoutes(router *gin.Engine) {

router.POST("/core/applications/verify", VerifyClientCredentials)
router.GET("/core/applications/client/:clientID/groups", GetApplicationGroupsByClientID)
router.GET("/core/saml/sp/entity/:entityID", GetSAMLServiceProviderByEntityID)
router.POST("/core/saml/sp/resolve", ResolveSAMLServiceProvider)
router.POST("/core/login/email-password", LoginEmailPassword)

router.GET("/entities/@me", GetMe)
Expand Down
19 changes: 16 additions & 3 deletions core/api/saml_sp.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,26 @@ func DeleteApplicationSAML(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "saml service provider deleted"})
}

// GetSAMLServiceProviderByEntityID resolves a SAML SP by its entityID. Internal
type resolveSAMLRequest struct {
EntityID string `json:"entity_id" binding:"required"`
}

// ResolveSAMLServiceProvider resolves a SAML SP by its entityID. Internal
// (/core) route, unauthenticated, for service-to-service use by the saml
// service when it handles an inbound AuthnRequest — it returns the owning
// application's client_id so the saml service can run the same access gate and
// group filtering OAuth uses.
func GetSAMLServiceProviderByEntityID(c *gin.Context) {
sp, err := service.GetResolvedSAMLServiceProviderByEntityID(c.Param("entityID"))
//
// The entityID is passed in the request body, not the path: SAML entity IDs are
// typically URLs (e.g. https://sp.example.com/metadata) whose `://` and slashes
// break a single-segment path param.
func ResolveSAMLServiceProvider(c *gin.Context) {
var req resolveSAMLRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
sp, err := service.GetResolvedSAMLServiceProviderByEntityID(req.EntityID)
if err != nil {
if err == gorm.ErrRecordNotFound {
c.JSON(http.StatusNotFound, gin.H{"error": "saml service provider not found"})
Expand Down
6 changes: 4 additions & 2 deletions saml/service/sp_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@ type ResolvedSP struct {
}

// ResolveSP fetches the SP registration for a SAML entityID from core. Returns
// sentinel.APIError (with Status 404) when no SP is registered for the id.
// sentinel.APIError (with Status 404) when no SP is registered for the id. The
// entityID is sent in the request body, not the path: SAML entity IDs are
// usually URLs whose `://` and slashes break a path segment.
func ResolveSP(entityID string) (ResolvedSP, error) {
var sp ResolvedSP
if err := sentinel.Get("/api/core/saml/sp/entity/"+entityID, &sp); err != nil {
if err := sentinel.Post("/api/core/saml/sp/resolve", map[string]string{"entity_id": entityID}, &sp); err != nil {
return ResolvedSP{}, err
}
return sp, nil
Expand Down
Loading