1package github 2 3import ( 4 "context" 5 "fmt" 6 "net/url" 7 "strings" 8 "time" 9 10 "github.com/hashicorp/errwrap" 11 "github.com/hashicorp/vault/sdk/framework" 12 "github.com/hashicorp/vault/sdk/helper/tokenutil" 13 "github.com/hashicorp/vault/sdk/logical" 14) 15 16func pathConfig(b *backend) *framework.Path { 17 p := &framework.Path{ 18 Pattern: "config", 19 Fields: map[string]*framework.FieldSchema{ 20 "organization": &framework.FieldSchema{ 21 Type: framework.TypeString, 22 Description: "The organization users must be part of", 23 }, 24 25 "base_url": &framework.FieldSchema{ 26 Type: framework.TypeString, 27 Description: `The API endpoint to use. Useful if you 28are running GitHub Enterprise or an 29API-compatible authentication server.`, 30 DisplayAttrs: &framework.DisplayAttributes{ 31 Name: "Base URL", 32 Group: "GitHub Options", 33 }, 34 }, 35 "ttl": &framework.FieldSchema{ 36 Type: framework.TypeDurationSecond, 37 Description: tokenutil.DeprecationText("token_ttl"), 38 Deprecated: true, 39 }, 40 "max_ttl": &framework.FieldSchema{ 41 Type: framework.TypeDurationSecond, 42 Description: tokenutil.DeprecationText("token_max_ttl"), 43 Deprecated: true, 44 }, 45 }, 46 47 Callbacks: map[logical.Operation]framework.OperationFunc{ 48 logical.UpdateOperation: b.pathConfigWrite, 49 logical.ReadOperation: b.pathConfigRead, 50 }, 51 } 52 53 tokenutil.AddTokenFields(p.Fields) 54 p.Fields["token_policies"].Description += ". This will apply to all tokens generated by this auth method, in addition to any policies configured for specific users/groups." 55 return p 56} 57 58func (b *backend) pathConfigWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { 59 c, err := b.Config(ctx, req.Storage) 60 if err != nil { 61 return nil, err 62 } 63 if c == nil { 64 c = &config{} 65 } 66 67 if organizationRaw, ok := data.GetOk("organization"); ok { 68 c.Organization = organizationRaw.(string) 69 } 70 71 if baseURLRaw, ok := data.GetOk("base_url"); ok { 72 baseURL := baseURLRaw.(string) 73 _, err := url.Parse(baseURL) 74 if err != nil { 75 return logical.ErrorResponse(fmt.Sprintf("Error parsing given base_url: %s", err)), nil 76 } 77 if !strings.HasSuffix(baseURL, "/") { 78 baseURL += "/" 79 } 80 c.BaseURL = baseURL 81 } 82 83 if err := c.ParseTokenFields(req, data); err != nil { 84 return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest 85 } 86 87 // Handle upgrade cases 88 { 89 if err := tokenutil.UpgradeValue(data, "ttl", "token_ttl", &c.TTL, &c.TokenTTL); err != nil { 90 return logical.ErrorResponse(err.Error()), nil 91 } 92 93 if err := tokenutil.UpgradeValue(data, "max_ttl", "token_max_ttl", &c.MaxTTL, &c.TokenMaxTTL); err != nil { 94 return logical.ErrorResponse(err.Error()), nil 95 } 96 } 97 98 entry, err := logical.StorageEntryJSON("config", c) 99 if err != nil { 100 return nil, err 101 } 102 103 if err := req.Storage.Put(ctx, entry); err != nil { 104 return nil, err 105 } 106 107 return nil, nil 108} 109 110func (b *backend) pathConfigRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) { 111 config, err := b.Config(ctx, req.Storage) 112 if err != nil { 113 return nil, err 114 } 115 if config == nil { 116 return nil, nil 117 } 118 119 d := map[string]interface{}{ 120 "organization": config.Organization, 121 "base_url": config.BaseURL, 122 } 123 config.PopulateTokenData(d) 124 125 if config.TTL > 0 { 126 d["ttl"] = int64(config.TTL.Seconds()) 127 } 128 if config.MaxTTL > 0 { 129 d["max_ttl"] = int64(config.MaxTTL.Seconds()) 130 } 131 132 return &logical.Response{ 133 Data: d, 134 }, nil 135} 136 137// Config returns the configuration for this backend. 138func (b *backend) Config(ctx context.Context, s logical.Storage) (*config, error) { 139 entry, err := s.Get(ctx, "config") 140 if err != nil { 141 return nil, err 142 } 143 if entry == nil { 144 return nil, nil 145 } 146 147 var result config 148 if entry != nil { 149 if err := entry.DecodeJSON(&result); err != nil { 150 return nil, errwrap.Wrapf("error reading configuration: {{err}}", err) 151 } 152 } 153 154 if result.TokenTTL == 0 && result.TTL > 0 { 155 result.TokenTTL = result.TTL 156 } 157 if result.TokenMaxTTL == 0 && result.MaxTTL > 0 { 158 result.TokenMaxTTL = result.MaxTTL 159 } 160 161 return &result, nil 162} 163 164type config struct { 165 tokenutil.TokenParams 166 167 Organization string `json:"organization" structs:"organization" mapstructure:"organization"` 168 BaseURL string `json:"base_url" structs:"base_url" mapstructure:"base_url"` 169 TTL time.Duration `json:"ttl" structs:"ttl" mapstructure:"ttl"` 170 MaxTTL time.Duration `json:"max_ttl" structs:"max_ttl" mapstructure:"max_ttl"` 171} 172