From c2fa94029935832e2125ddf29bb0068ccb38bdb3 Mon Sep 17 00:00:00 2001 From: Tamas Kiss Date: Mon, 23 May 2022 12:28:33 +0200 Subject: [PATCH] Adding gitea_oauth_app resource --- docs/resources/oauth2_app.md | 29 +++++ gitea/provider.go | 1 + gitea/resource_gitea_oauth_app.go | 195 ++++++++++++++++++++++++++++++ 3 files changed, 225 insertions(+) create mode 100644 docs/resources/oauth2_app.md create mode 100644 gitea/resource_gitea_oauth_app.go diff --git a/docs/resources/oauth2_app.md b/docs/resources/oauth2_app.md new file mode 100644 index 0000000..ae200f1 --- /dev/null +++ b/docs/resources/oauth2_app.md @@ -0,0 +1,29 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "gitea_oauth2_app Resource - terraform-provider-gitea" +subcategory: "" +description: |- + Handling gitea oauth application https://docs.gitea.io/en-us/oauth2-provider/ resources +--- + +# gitea_oauth2_app (Resource) + +Handling [gitea oauth application](https://docs.gitea.io/en-us/oauth2-provider/) resources + + + + +## Schema + +### Required + +- `name` (String) OAuth Application name +- `redirect_uris` (Set of String) Accepted redirect URIs + +### Read-Only + +- `client_id` (String) OAuth2 client id +- `client_secret` (String, Sensitive) Oauth2 client secret +- `id` (String) The ID of this resource. + + diff --git a/gitea/provider.go b/gitea/provider.go index 9909fae..79a8ca9 100644 --- a/gitea/provider.go +++ b/gitea/provider.go @@ -77,6 +77,7 @@ func Provider() terraform.ResourceProvider { // "gitea_team": resourceGiteaTeam(), // "gitea_repo": resourceGiteaRepo(), // "gitea_user": resourceGiteaUser(), + "gitea_oauth2_app": resourceGiteaOauthApp(), }, ConfigureFunc: providerConfigure, diff --git a/gitea/resource_gitea_oauth_app.go b/gitea/resource_gitea_oauth_app.go new file mode 100644 index 0000000..4ff217f --- /dev/null +++ b/gitea/resource_gitea_oauth_app.go @@ -0,0 +1,195 @@ +package gitea + +import ( + "fmt" + + "code.gitea.io/sdk/gitea" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +const ( + oauth2KeyName string = "name" + oauth2KeyRedirectURIs string = "redirect_uris" + oauth2KeyClientId string = "client_id" + oauth2KeyClientSecret string = "client_secret" +) + +func resourceGiteaOauthApp() *schema.Resource { + return &schema.Resource{ + Read: resourceOauth2AppRead, + Create: resourceOauth2AppUpcreate, + Update: resourceOauth2AppUpcreate, + Delete: resourceOauth2AppDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + oauth2KeyName: { + Required: true, + Type: schema.TypeString, + Description: "OAuth Application name", + }, + oauth2KeyRedirectURIs: { + Required: true, + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Description: "Accepted redirect URIs", + }, + oauth2KeyClientId: { + Type: schema.TypeString, + Computed: true, + Description: "OAuth2 Application client id", + }, + oauth2KeyClientSecret: { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "Oauth2 Application client secret", + }, + }, + Description: "Handling [gitea oauth application](https://docs.gitea.io/en-us/oauth2-provider/) resources", + } +} + +func ExpandStringList(configured []interface{}) []string { + res := make([]string, 0, len(configured)) + for _, v := range configured { + val, ok := v.(string) + if ok && val != "" { + res = append(res, (v.(string))) + } + } + return res +} + +func CollapseStringList(strlist []string) []interface{} { + res := make([]interface{}, 0, len(strlist)) + for _, v := range strlist { + res = append(res, v) + } + return res +} + +func resourceOauth2AppUpcreate(d *schema.ResourceData, meta interface{}) (err error) { + client := meta.(*gitea.Client) + + redirectURIsSchema, redirectURIsSchemaOk := d.Get(oauth2KeyRedirectURIs).(*schema.Set) + + if !redirectURIsSchemaOk { + return fmt.Errorf("attribute %s must be set to a set of strings", oauth2KeyRedirectURIs) + } + + redirectURIs := ExpandStringList(redirectURIsSchema.List()) + + name, nameOk := d.Get(oauth2KeyName).(string) + + if !nameOk { + return fmt.Errorf("attribute %s must be set and must be a string", oauth2KeyName) + } + + opts := gitea.CreateOauth2Option{ + Name: name, + RedirectURIs: redirectURIs, + } + + var oauth2 *gitea.Oauth2 + + if d.IsNewResource() { + oauth2, _, err = client.CreateOauth2(opts) + } else { + oauth2, err := searchOauth2AppByClientId(client, d.Id()) + + if err != nil { + return err + } + + oauth2, _, err = client.UpdateOauth2(oauth2.ID, opts) + } + + if err != nil { + return + } + + err = setOAuth2ResourceData(oauth2, d) + + return +} + +func searchOauth2AppByClientId(c *gitea.Client, id string) (res *gitea.Oauth2, err error) { + page := 1 + + for { + apps, _, err := c.ListOauth2(gitea.ListOauth2Option{ + ListOptions: gitea.ListOptions{ + Page: page, + PageSize: 50, + }, + }) + if err != nil { + return nil, err + } + if len(apps) == 0 { + return nil, fmt.Errorf("no oauth client can be found by id '%s'", id) + } + + for _, app := range apps { + if app.ClientID == id { + return app, nil + } + } + + page += 1 + } +} + +func resourceOauth2AppRead(d *schema.ResourceData, meta interface{}) (err error) { + client := meta.(*gitea.Client) + + app, err := searchOauth2AppByClientId(client, d.Id()) + + if err != nil { + return err + } + + err = setOAuth2ResourceData(app, d) + + return +} + +func resourceOauth2AppDelete(d *schema.ResourceData, meta interface{}) (err error) { + client := meta.(*gitea.Client) + + app, err := searchOauth2AppByClientId(client, d.Id()) + + if err != nil { + return err + } + + _, err = client.DeleteOauth2(app.ID) + + return +} + +func setOAuth2ResourceData(app *gitea.Oauth2, d *schema.ResourceData) (err error) { + d.SetId(app.ClientID) + + for k, v := range map[string]interface{}{ + oauth2KeyName: app.Name, + oauth2KeyRedirectURIs: schema.NewSet(schema.HashString, CollapseStringList(app.RedirectURIs)), + oauth2KeyClientId: app.ClientID, + } { + err = d.Set(k, v) + if err != nil { + return + } + } + + if app.ClientSecret != "" { + // Gitea API only reports client secrets if the resource is newly created + d.Set(oauth2KeyClientSecret, app.ClientSecret) + } + + return +}