diff --git a/modules/convert/auth_source.go b/modules/convert/auth_source.go new file mode 100644 index 0000000000000..f4b091aea7ec4 --- /dev/null +++ b/modules/convert/auth_source.go @@ -0,0 +1,42 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package convert + +import ( + "code.gitea.io/gitea/models" + api "code.gitea.io/gitea/modules/structs" +) + +// ToAuthSources convert a list of models.LoginSource to a list of api.AuthSource +func ToAuthSources(sources []*models.LoginSource) ([]*api.AuthSource, error) { + result := make([]*api.AuthSource, len(sources)) + for i, source := range sources { + authSource, err := ToAuthSource(source) + if err != nil { + return nil, err + } + result[i] = authSource + } + return result, nil +} + +// ToAuthSource convert a models.LoginSource to a api.AuthSource +func ToAuthSource(source *models.LoginSource) (*api.AuthSource, error) { + cfg, err := source.Cfg.ToDB() + if err != nil { + return nil, err + } + authSource := &api.AuthSource{ + ID: source.ID, + Name: source.Name, + Type: models.LoginNames[source.Type], + IsActive: source.IsActived, + IsSyncEnabled: source.IsSyncEnabled, + CreatedTime: source.CreatedUnix.AsTime(), + UpdatedTime: source.UpdatedUnix.AsTime(), + Cfg: cfg, + } + return authSource, nil +} diff --git a/modules/structs/auth_source.go b/modules/structs/auth_source.go new file mode 100644 index 0000000000000..741bee7062770 --- /dev/null +++ b/modules/structs/auth_source.go @@ -0,0 +1,38 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package structs + +import ( + "encoding/json" + "time" +) + +// AuthSource represents an authentication source +type AuthSource struct { + ID int64 `json:"id"` + Name string `json:"name"` + // enum: LDAP (via BindDN),LDAP (simple auth),SMTP,PAM,OAuth2,SPNEGO with SSPI + Type string `json:"type"` + IsActive bool `json:"isActive"` + IsSyncEnabled bool `json:"isSyncEnabled"` + // swagger:strfmt date-time + CreatedTime time.Time `json:"createdTime"` + // swagger:strfmt date-time + UpdatedTime time.Time `json:"updatedTime"` + Cfg json.RawMessage `json:"config"` +} + +// CreateAuthSource represents an authentication source creation request +type CreateAuthSource struct { + // required: true + Name string `json:"name" binding:"Required"` + // required: true + // enum: LDAP (via BindDN),LDAP (simple auth),SMTP,PAM,OAuth2,SPNEGO with SSPI + Type string `json:"type" binding:"Required"` + IsActive bool `json:"isActive"` + IsSyncEnabled bool `json:"isSyncEnabled"` + // required: true + Cfg json.RawMessage `json:"config" binding:"Required"` +} diff --git a/routers/api/v1/admin/auths.go b/routers/api/v1/admin/auths.go new file mode 100644 index 0000000000000..743ee62299add --- /dev/null +++ b/routers/api/v1/admin/auths.go @@ -0,0 +1,115 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package admin + +import ( + "net/http" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/convert" + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/web" + + xorm "xorm.io/xorm/convert" +) + +// ListAuthSources returns list of existing authentication sources +func ListAuthSources(ctx *context.APIContext) { + // swagger:operation GET /admin/auths admin adminAuthsSourcesList + // --- + // summary: List existing authentication sources + // produces: + // - application/json + // responses: + // "200": + // "$ref": "#/responses/AuthSourcesList" + // "403": + // "$ref": "#/responses/forbidden" + sources, err := models.LoginSources() + if err != nil { + ctx.InternalServerError(err) + return + } + result, err := convert.ToAuthSources(sources) + if err != nil { + ctx.InternalServerError(err) + return + } + ctx.JSON(http.StatusOK, result) +} + +// CreateAuthSource creates new authentication source +func CreateAuthSource(ctx *context.APIContext) { + // swagger:operation POST /admin/auths admin adminCreateAuthSource + // --- + // summary: Create new authentication source + // consumes: + // - application/json + // produces: + // - application/json + // parameters: + // - name: body + // in: body + // schema: + // "$ref": "#/definitions/CreateAuthSource" + // responses: + // "201": + // "$ref": "#/responses/AuthSource" + // "403": + // "$ref": "#/responses/forbidden" + authSource := web.GetForm(ctx).(*api.CreateAuthSource) + var config xorm.Conversion + var loginType models.LoginType + for key, val := range models.LoginNames { + if authSource.Type == val { + loginType = key + switch key { + case models.LoginLDAP: + config = &models.LDAPConfig{} + case models.LoginSMTP: + config = &models.SMTPConfig{} + case models.LoginPAM: + config = &models.PAMConfig{} + case models.LoginDLDAP: + config = &models.LDAPConfig{} + case models.LoginOAuth2: + config = &models.OAuth2Config{} + case models.LoginSSPI: + config = &models.SSPIConfig{} + } + break + } + } + if loginType == 0 { + ctx.Error(http.StatusBadRequest, "", "Authentication source type is invalid") + return + } + if err := config.FromDB(authSource.Cfg); err != nil { + ctx.InternalServerError(err) + return + } + + source := &models.LoginSource{ + Type: loginType, + Cfg: config, + Name: authSource.Name, + IsActived: authSource.IsActive, + IsSyncEnabled: authSource.IsSyncEnabled, + CreatedUnix: timeutil.TimeStampNow(), + UpdatedUnix: timeutil.TimeStampNow(), + } + if err := models.CreateLoginSource(source); err != nil { + ctx.InternalServerError(err) + return + } + result, err := convert.ToAuthSource(source) + if err != nil { + ctx.InternalServerError(err) + return + } + ctx.JSON(http.StatusCreated, result) +} diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index a8499e0ee8f6a..578d2e710bae9 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -1016,6 +1016,10 @@ func Routes() *web.Route { }, orgAssignment(false, true), reqToken(), reqTeamMembership()) m.Group("/admin", func() { + m.Group("/auths", func() { + m.Get("", admin.ListAuthSources) + m.Post("", bind(api.CreateAuthSource{}), admin.CreateAuthSource) + }) m.Group("/cron", func() { m.Get("", admin.ListCronTasks) m.Post("/{task}", admin.PostCronTask) diff --git a/routers/api/v1/swagger/auth_source.go b/routers/api/v1/swagger/auth_source.go new file mode 100644 index 0000000000000..fbca605945186 --- /dev/null +++ b/routers/api/v1/swagger/auth_source.go @@ -0,0 +1,28 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package swagger + +import api "code.gitea.io/gitea/modules/structs" + +// AuthSourcesList +// swagger:response AuthSourcesList +type swaggerAuthSourcesList struct { + // in:body + Body []api.AuthSource `json:"body"` +} + +// AuthSource +// swagger:response AuthSource +type swaggerAuthSource struct { + // in:body + Body api.AuthSource `json:"body"` +} + +// CreateAuthSource +// swagger:response CreateAuthSource +type swaggerCreateAuthSource struct { + // in:body + CreateAuthSource api.CreateAuthSource +} diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 4a97650e56a73..5112d6a87ee88 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -23,6 +23,56 @@ }, "basePath": "{{AppSubUrl}}/api/v1", "paths": { + "/admin/auths": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "admin" + ], + "summary": "List existing authentication sources", + "operationId": "adminAuthsSourcesList", + "responses": { + "200": { + "$ref": "#/responses/AuthSourcesList" + }, + "403": { + "$ref": "#/responses/forbidden" + } + } + }, + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "admin" + ], + "summary": "Create new authentication source", + "operationId": "adminCreateAuthSource", + "parameters": [ + { + "name": "body", + "in": "body", + "schema": { + "$ref": "#/definitions/CreateAuthSource" + } + } + ], + "responses": { + "201": { + "$ref": "#/responses/AuthSource" + }, + "403": { + "$ref": "#/responses/forbidden" + } + } + } + }, "/admin/cron": { "get": { "produces": [ @@ -11714,6 +11764,56 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "AuthSource": { + "description": "AuthSource represents an authentication source", + "type": "object", + "properties": { + "config": { + "type": "object", + "x-go-name": "Cfg" + }, + "createdTime": { + "type": "string", + "format": "date-time", + "x-go-name": "CreatedTime" + }, + "id": { + "type": "integer", + "format": "int64", + "x-go-name": "ID" + }, + "isActive": { + "type": "boolean", + "x-go-name": "IsActive" + }, + "isSyncEnabled": { + "type": "boolean", + "x-go-name": "IsSyncEnabled" + }, + "name": { + "type": "string", + "x-go-name": "Name" + }, + "type": { + "type": "string", + "enum": [ + "LDAP (via BindDN)", + "LDAP (simple auth)", + "SMTP", + "PAM", + "OAuth2", + "SPNEGO with SSPI" + ], + "x-go-name": "Type" + }, + "updatedTime": { + "type": "string", + "format": "date-time", + "x-go-name": "UpdatedTime" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, "Branch": { "description": "Branch represents a repository branch", "type": "object", @@ -12202,6 +12302,46 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "CreateAuthSource": { + "description": "CreateAuthSource represents an authentication source creation request", + "type": "object", + "required": [ + "name", + "type", + "config" + ], + "properties": { + "config": { + "type": "object", + "x-go-name": "Cfg" + }, + "isActive": { + "type": "boolean", + "x-go-name": "IsActive" + }, + "isSyncEnabled": { + "type": "boolean", + "x-go-name": "IsSyncEnabled" + }, + "name": { + "type": "string", + "x-go-name": "Name" + }, + "type": { + "type": "string", + "enum": [ + "LDAP (via BindDN)", + "LDAP (simple auth)", + "SMTP", + "PAM", + "OAuth2", + "SPNEGO with SSPI" + ], + "x-go-name": "Type" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, "CreateBranchProtectionOption": { "description": "CreateBranchProtectionOption options for creating a branch protection", "type": "object", @@ -16327,6 +16467,21 @@ } } }, + "AuthSource": { + "description": "AuthSource", + "schema": { + "$ref": "#/definitions/AuthSource" + } + }, + "AuthSourcesList": { + "description": "AuthSourcesList", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/AuthSource" + } + } + }, "Branch": { "description": "Branch", "schema": { @@ -16449,6 +16604,12 @@ "$ref": "#/definitions/ContentsResponse" } }, + "CreateAuthSource": { + "description": "CreateAuthSource", + "schema": { + "$ref": "#/definitions/CreateAuthSource" + } + }, "CronList": { "description": "CronList", "schema": {