feat: auth provider REST API and public provider discovery
This commit is contained in:
@@ -65,6 +65,12 @@ func HandleLocalLogin(c *gin.Context) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
// The login page hides the form, but the page is a courtesy and the API is
|
||||
// the boundary.
|
||||
if !services.IsLocalLoginEnabled(instanceID) {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "password sign-in is disabled for this instance"})
|
||||
return
|
||||
}
|
||||
u, err := services.GetUserInInstanceByEmail(instanceID, body.Email)
|
||||
if err != nil || !services.VerifyPassword(u, body.Password) {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid credentials"})
|
||||
@@ -82,6 +88,45 @@ func HandleLocalLogin(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true})
|
||||
}
|
||||
|
||||
// HandleListPublicProviders is unauthenticated: it is what the login page reads
|
||||
// to decide what to draw. It carries no issuer, no client ID and no secret —
|
||||
// only what a button needs, because anyone who can reach the login page can
|
||||
// read this.
|
||||
func HandleListPublicProviders(c *gin.Context) {
|
||||
type publicProvider struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Preset string `json:"preset"`
|
||||
}
|
||||
out := []publicProvider{}
|
||||
|
||||
instanceID, err := resolveLoginInstance(c)
|
||||
if err != nil {
|
||||
// An unresolvable instance is not an error the login page can act on:
|
||||
// it still has to render a password form. Answer the safe shape.
|
||||
c.JSON(http.StatusOK, gin.H{"local_enabled": true, "providers": out})
|
||||
return
|
||||
}
|
||||
|
||||
// A lapsed licence stops SSO, so a button that cannot work is not offered.
|
||||
if services.GetLicenseState(instanceID).Feature("oidc") {
|
||||
providers, err := services.ListEnabledAuthProviders(instanceID)
|
||||
if err == nil {
|
||||
for _, p := range providers {
|
||||
out = append(out, publicProvider{ID: p.ProviderID, Name: p.Name, Preset: p.Preset})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
localEnabled := services.IsLocalLoginEnabled(instanceID)
|
||||
// Belt and braces against a hand-edited database: a login page with neither
|
||||
// a form nor a button is unrecoverable without database access.
|
||||
if !localEnabled && len(out) == 0 {
|
||||
localEnabled = true
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"local_enabled": localEnabled, "providers": out})
|
||||
}
|
||||
|
||||
func HandleBootstrapStatus(c *gin.Context) {
|
||||
var (
|
||||
n int64
|
||||
|
||||
Reference in New Issue
Block a user