1
0

remove auth/github

This commit is contained in:
Konstantin Demin 2024-07-01 21:19:59 +03:00
parent 73a3de957a
commit 749fdf1017
23 changed files with 2 additions and 1577 deletions

View File

@ -1,129 +0,0 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package github
import (
"context"
"net/url"
"github.com/google/go-github/github"
cleanhttp "github.com/hashicorp/go-cleanhttp"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/logical"
"golang.org/x/oauth2"
)
const operationPrefixGithub = "github"
func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error) {
b := Backend()
if err := b.Setup(ctx, conf); err != nil {
return nil, err
}
return b, nil
}
func Backend() *backend {
var b backend
b.TeamMap = &framework.PolicyMap{
PathMap: framework.PathMap{
Name: "teams",
},
DefaultKey: "default",
}
teamMapPaths := b.TeamMap.Paths()
teamMapPaths[0].DisplayAttrs = &framework.DisplayAttributes{
OperationPrefix: operationPrefixGithub,
OperationSuffix: "teams",
}
teamMapPaths[1].DisplayAttrs = &framework.DisplayAttributes{
OperationPrefix: operationPrefixGithub,
OperationSuffix: "team-mapping",
}
b.UserMap = &framework.PolicyMap{
PathMap: framework.PathMap{
Name: "users",
},
DefaultKey: "default",
}
userMapPaths := b.UserMap.Paths()
userMapPaths[0].DisplayAttrs = &framework.DisplayAttributes{
OperationPrefix: operationPrefixGithub,
OperationSuffix: "users",
}
userMapPaths[1].DisplayAttrs = &framework.DisplayAttributes{
OperationPrefix: operationPrefixGithub,
OperationSuffix: "user-mapping",
}
allPaths := append(teamMapPaths, userMapPaths...)
b.Backend = &framework.Backend{
Help: backendHelp,
PathsSpecial: &logical.Paths{
Unauthenticated: []string{
"login",
},
},
Paths: append([]*framework.Path{pathConfig(&b), pathLogin(&b)}, allPaths...),
AuthRenew: b.pathLoginRenew,
BackendType: logical.TypeCredential,
}
return &b
}
type backend struct {
*framework.Backend
TeamMap *framework.PolicyMap
UserMap *framework.PolicyMap
}
// Client returns the GitHub client to communicate to GitHub via the
// configured settings.
func (b *backend) Client(token string) (*github.Client, error) {
tc := cleanhttp.DefaultClient()
if token != "" {
ctx := context.WithValue(context.Background(), oauth2.HTTPClient, tc)
tc = oauth2.NewClient(ctx, &tokenSource{Value: token})
}
client := github.NewClient(tc)
emptyUrl, err := url.Parse("")
if err != nil {
return nil, err
}
client.UploadURL = emptyUrl
return client, nil
}
// tokenSource is an oauth2.TokenSource implementation.
type tokenSource struct {
Value string
}
func (t *tokenSource) Token() (*oauth2.Token, error) {
return &oauth2.Token{AccessToken: t.Value}, nil
}
const backendHelp = `
The GitHub credential provider allows authentication via GitHub.
Users provide a personal access token to log in, and the credential
provider verifies they're part of the correct organization and then
maps the user to a set of Vault policies according to the teams they're
part of.
After enabling the credential provider, use the "config" route to
configure it.
`

View File

@ -1,213 +0,0 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package github
import (
"context"
"errors"
"fmt"
"os"
"strings"
"testing"
"time"
logicaltest "github.com/hashicorp/vault/helper/testhelpers/logical"
"github.com/hashicorp/vault/sdk/logical"
)
func TestBackend_Config(t *testing.T) {
defaultLeaseTTLVal := time.Hour * 24
maxLeaseTTLVal := time.Hour * 24 * 2
b, err := Factory(context.Background(), &logical.BackendConfig{
Logger: nil,
System: &logical.StaticSystemView{
DefaultLeaseTTLVal: defaultLeaseTTLVal,
MaxLeaseTTLVal: maxLeaseTTLVal,
},
})
if err != nil {
t.Fatalf("Unable to create backend: %s", err)
}
login_data := map[string]interface{}{
// This token has to be replaced with a working token for the test to work.
"token": os.Getenv("GITHUB_TOKEN"),
}
config_data1 := map[string]interface{}{
"organization": os.Getenv("GITHUB_ORG"),
"ttl": "",
"max_ttl": "",
}
expectedTTL1 := 24 * time.Hour
config_data2 := map[string]interface{}{
"organization": os.Getenv("GITHUB_ORG"),
"ttl": "1h",
"max_ttl": "2h",
}
expectedTTL2 := time.Hour
config_data3 := map[string]interface{}{
"organization": os.Getenv("GITHUB_ORG"),
"ttl": "50h",
"max_ttl": "50h",
}
expectedTTL3 := 48 * time.Hour
logicaltest.Test(t, logicaltest.TestCase{
PreCheck: func() { testAccPreCheck(t) },
CredentialBackend: b,
Steps: []logicaltest.TestStep{
testConfigWrite(t, config_data1),
testLoginWrite(t, login_data, expectedTTL1, false),
testConfigWrite(t, config_data2),
testLoginWrite(t, login_data, expectedTTL2, false),
testConfigWrite(t, config_data3),
testLoginWrite(t, login_data, expectedTTL3, true),
},
})
}
func testLoginWrite(t *testing.T, d map[string]interface{}, expectedTTL time.Duration, expectFail bool) logicaltest.TestStep {
return logicaltest.TestStep{
Operation: logical.UpdateOperation,
Path: "login",
ErrorOk: true,
Data: d,
Check: func(resp *logical.Response) error {
if resp == nil {
return errors.New("expected a response but got nil")
}
if resp.IsError() && expectFail {
return nil
}
actualTTL := resp.Auth.LeaseOptions.TTL
if actualTTL != expectedTTL {
return fmt.Errorf("TTL mismatched. Expected: %d Actual: %d", expectedTTL, resp.Auth.LeaseOptions.TTL)
}
return nil
},
}
}
func testConfigWrite(t *testing.T, d map[string]interface{}) logicaltest.TestStep {
return logicaltest.TestStep{
Operation: logical.UpdateOperation,
Path: "config",
Data: d,
}
}
func TestBackend_basic(t *testing.T) {
defaultLeaseTTLVal := time.Hour * 24
maxLeaseTTLVal := time.Hour * 24 * 32
b, err := Factory(context.Background(), &logical.BackendConfig{
Logger: nil,
System: &logical.StaticSystemView{
DefaultLeaseTTLVal: defaultLeaseTTLVal,
MaxLeaseTTLVal: maxLeaseTTLVal,
},
})
if err != nil {
t.Fatalf("Unable to create backend: %s", err)
}
logicaltest.Test(t, logicaltest.TestCase{
PreCheck: func() { testAccPreCheck(t) },
CredentialBackend: b,
Steps: []logicaltest.TestStep{
testAccStepConfig(t, false),
testAccMap(t, "default", "fakepol"),
testAccMap(t, "oWnErs", "fakepol"),
testAccLogin(t, []string{"default", "abc", "fakepol"}),
testAccStepConfig(t, true),
testAccMap(t, "default", "fakepol"),
testAccMap(t, "oWnErs", "fakepol"),
testAccLogin(t, []string{"default", "abc", "fakepol"}),
testAccStepConfigWithBaseURL(t),
testAccMap(t, "default", "fakepol"),
testAccMap(t, "oWnErs", "fakepol"),
testAccLogin(t, []string{"default", "abc", "fakepol"}),
testAccMap(t, "default", "fakepol"),
testAccStepConfig(t, true),
mapUserToPolicy(t, os.Getenv("GITHUB_USER"), "userpolicy"),
testAccLogin(t, []string{"default", "abc", "fakepol", "userpolicy"}),
},
})
}
func testAccPreCheck(t *testing.T) {
if v := os.Getenv("GITHUB_TOKEN"); v == "" {
t.Skip("GITHUB_TOKEN must be set for acceptance tests")
}
if v := os.Getenv("GITHUB_USER"); v == "" {
t.Skip("GITHUB_USER must be set for acceptance tests")
}
if v := os.Getenv("GITHUB_ORG"); v == "" {
t.Skip("GITHUB_ORG must be set for acceptance tests")
}
if v := os.Getenv("GITHUB_BASEURL"); v == "" {
t.Skip("GITHUB_BASEURL must be set for acceptance tests (use 'https://api.github.com' if you don't know what you're doing)")
}
}
func testAccStepConfig(t *testing.T, upper bool) logicaltest.TestStep {
ts := logicaltest.TestStep{
Operation: logical.UpdateOperation,
Path: "config",
Data: map[string]interface{}{
"organization": os.Getenv("GITHUB_ORG"),
"token_policies": []string{"abc"},
},
}
if upper {
ts.Data["organization"] = strings.ToUpper(os.Getenv("GITHUB_ORG"))
}
return ts
}
func testAccStepConfigWithBaseURL(t *testing.T) logicaltest.TestStep {
return logicaltest.TestStep{
Operation: logical.UpdateOperation,
Path: "config",
Data: map[string]interface{}{
"organization": os.Getenv("GITHUB_ORG"),
"base_url": os.Getenv("GITHUB_BASEURL"),
},
}
}
func testAccMap(t *testing.T, k string, v string) logicaltest.TestStep {
return logicaltest.TestStep{
Operation: logical.UpdateOperation,
Path: "map/teams/" + k,
Data: map[string]interface{}{
"value": v,
},
}
}
func mapUserToPolicy(t *testing.T, k string, v string) logicaltest.TestStep {
return logicaltest.TestStep{
Operation: logical.UpdateOperation,
Path: "map/users/" + k,
Data: map[string]interface{}{
"value": v,
},
}
}
func testAccLogin(t *testing.T, policies []string) logicaltest.TestStep {
return logicaltest.TestStep{
Operation: logical.UpdateOperation,
Path: "login",
Data: map[string]interface{}{
"token": os.Getenv("GITHUB_TOKEN"),
},
Unauthenticated: true,
Check: logicaltest.TestCheckAuth(policies),
}
}

View File

@ -1,97 +0,0 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package github
import (
"fmt"
"io"
"os"
"strings"
"github.com/hashicorp/go-secure-stdlib/password"
"github.com/hashicorp/vault/api"
)
type CLIHandler struct {
// for tests
testStdout io.Writer
}
func (h *CLIHandler) Auth(c *api.Client, m map[string]string) (*api.Secret, error) {
mount, ok := m["mount"]
if !ok {
mount = "github"
}
// Extract or prompt for token
token := m["token"]
if token == "" {
token = os.Getenv("VAULT_AUTH_GITHUB_TOKEN")
}
if token == "" {
// Override the output
stdout := h.testStdout
if stdout == nil {
stdout = os.Stderr
}
var err error
fmt.Fprintf(stdout, "GitHub Personal Access Token (will be hidden): ")
token, err = password.Read(os.Stdin)
fmt.Fprintf(stdout, "\n")
if err != nil {
if err == password.ErrInterrupted {
return nil, fmt.Errorf("user interrupted")
}
return nil, fmt.Errorf("An error occurred attempting to "+
"ask for a token. The raw error message is shown below, but usually "+
"this is because you attempted to pipe a value into the command or "+
"you are executing outside of a terminal (tty). If you want to pipe "+
"the value, pass \"-\" as the argument to read from stdin. The raw "+
"error was: %w", err)
}
}
path := fmt.Sprintf("auth/%s/login", mount)
secret, err := c.Logical().Write(path, map[string]interface{}{
"token": strings.TrimSpace(token),
})
if err != nil {
return nil, err
}
if secret == nil {
return nil, fmt.Errorf("empty response from credential provider")
}
return secret, nil
}
func (h *CLIHandler) Help() string {
help := `
Usage: vault login -method=github [CONFIG K=V...]
The GitHub auth method allows users to authenticate using a GitHub
personal access token. Users can generate a personal access token from the
settings page on their GitHub account.
Authenticate using a GitHub token:
$ vault login -method=github token=abcd1234
Configuration:
mount=<string>
Path where the GitHub credential method is mounted. This is usually
provided via the -path flag in the "vault login" command, but it can be
specified here as well. If specified here, it takes precedence over the
value for -path. The default value is "github".
token=<string>
GitHub personal access token to use for authentication. If not provided,
Vault will prompt for the value.
`
return strings.TrimSpace(help)
}

View File

@ -1,34 +0,0 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package main
import (
"os"
hclog "github.com/hashicorp/go-hclog"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/builtin/credential/github"
"github.com/hashicorp/vault/sdk/plugin"
)
func main() {
apiClientMeta := &api.PluginAPIClientMeta{}
flags := apiClientMeta.FlagSet()
flags.Parse(os.Args[1:])
tlsConfig := apiClientMeta.GetTLSConfig()
tlsProviderFunc := api.VaultPluginTLSProvider(tlsConfig)
if err := plugin.ServeMultiplex(&plugin.ServeOpts{
BackendFactoryFunc: github.Factory,
// set the TLSProviderFunc so that the plugin maintains backwards
// compatibility with Vault versions that dont support plugin AutoMTLS
TLSProviderFunc: tlsProviderFunc,
}); err != nil {
logger := hclog.New(&hclog.LoggerOptions{})
logger.Error("plugin shutting down", "error", err)
os.Exit(1)
}
}

View File

@ -1,247 +0,0 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package github
import (
"context"
"fmt"
"net/url"
"os"
"strings"
"time"
"github.com/google/go-github/github"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/tokenutil"
"github.com/hashicorp/vault/sdk/logical"
)
func pathConfig(b *backend) *framework.Path {
p := &framework.Path{
Pattern: "config",
DisplayAttrs: &framework.DisplayAttributes{
OperationPrefix: operationPrefixGithub,
},
Fields: map[string]*framework.FieldSchema{
"organization": {
Type: framework.TypeString,
Description: "The organization users must be part of",
Required: true,
},
"organization_id": {
Type: framework.TypeInt64,
Description: "The ID of the organization users must be part of",
},
"base_url": {
Type: framework.TypeString,
Description: `The API endpoint to use. Useful if you
are running GitHub Enterprise or an
API-compatible authentication server.`,
DisplayAttrs: &framework.DisplayAttributes{
Name: "Base URL",
Group: "GitHub Options",
},
},
"ttl": {
Type: framework.TypeDurationSecond,
Description: tokenutil.DeprecationText("token_ttl"),
Deprecated: true,
},
"max_ttl": {
Type: framework.TypeDurationSecond,
Description: tokenutil.DeprecationText("token_max_ttl"),
Deprecated: true,
},
},
Operations: map[logical.Operation]framework.OperationHandler{
logical.UpdateOperation: &framework.PathOperation{
Callback: b.pathConfigWrite,
DisplayAttrs: &framework.DisplayAttributes{
OperationPrefix: operationPrefixGithub,
OperationVerb: "configure",
},
},
logical.ReadOperation: &framework.PathOperation{
Callback: b.pathConfigRead,
DisplayAttrs: &framework.DisplayAttributes{
OperationSuffix: "configuration",
},
},
},
}
tokenutil.AddTokenFields(p.Fields)
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."
return p
}
func (b *backend) pathConfigWrite(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
var resp logical.Response
c, err := b.Config(ctx, req.Storage)
if err != nil {
return nil, err
}
if c == nil {
c = &config{}
}
if organizationRaw, ok := data.GetOk("organization"); ok {
c.Organization = organizationRaw.(string)
}
if c.Organization == "" {
return logical.ErrorResponse("organization is a required parameter"), nil
}
if organizationRaw, ok := data.GetOk("organization_id"); ok {
c.OrganizationID = organizationRaw.(int64)
}
var parsedURL *url.URL
if baseURLRaw, ok := data.GetOk("base_url"); ok {
baseURL := baseURLRaw.(string)
if !strings.HasSuffix(baseURL, "/") {
baseURL += "/"
}
parsedURL, err = url.Parse(baseURL)
if err != nil {
return logical.ErrorResponse(fmt.Sprintf("error parsing given base_url: %s", err)), nil
}
c.BaseURL = baseURL
}
if c.OrganizationID == 0 {
githubToken := os.Getenv("VAULT_AUTH_CONFIG_GITHUB_TOKEN")
client, err := b.Client(githubToken)
if err != nil {
return nil, err
}
// ensure our client has the BaseURL if it was provided
if parsedURL != nil {
client.BaseURL = parsedURL
}
// we want to set the Org ID in the config so we can use that to verify
// the credentials on login
err = c.setOrganizationID(ctx, client)
if err != nil {
errorMsg := fmt.Errorf("unable to fetch the organization_id, you must manually set it in the config: %s", err)
b.Logger().Error(errorMsg.Error())
return nil, errorMsg
}
}
if err := c.ParseTokenFields(req, data); err != nil {
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
}
// Handle upgrade cases
{
if err := tokenutil.UpgradeValue(data, "ttl", "token_ttl", &c.TTL, &c.TokenTTL); err != nil {
return logical.ErrorResponse(err.Error()), nil
}
if err := tokenutil.UpgradeValue(data, "max_ttl", "token_max_ttl", &c.MaxTTL, &c.TokenMaxTTL); err != nil {
return logical.ErrorResponse(err.Error()), nil
}
}
entry, err := logical.StorageEntryJSON("config", c)
if err != nil {
return nil, err
}
if err := req.Storage.Put(ctx, entry); err != nil {
return nil, err
}
if len(resp.Warnings) == 0 {
return nil, nil
}
return &resp, nil
}
func (b *backend) pathConfigRead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
config, err := b.Config(ctx, req.Storage)
if err != nil {
return nil, err
}
if config == nil {
return nil, nil
}
d := map[string]interface{}{
"organization_id": config.OrganizationID,
"organization": config.Organization,
"base_url": config.BaseURL,
}
config.PopulateTokenData(d)
if config.TTL > 0 {
d["ttl"] = int64(config.TTL.Seconds())
}
if config.MaxTTL > 0 {
d["max_ttl"] = int64(config.MaxTTL.Seconds())
}
return &logical.Response{
Data: d,
}, nil
}
// Config returns the configuration for this backend.
func (b *backend) Config(ctx context.Context, s logical.Storage) (*config, error) {
entry, err := s.Get(ctx, "config")
if err != nil {
return nil, err
}
if entry == nil {
return nil, nil
}
var result config
if entry != nil {
if err := entry.DecodeJSON(&result); err != nil {
return nil, fmt.Errorf("error reading configuration: %w", err)
}
}
if result.TokenTTL == 0 && result.TTL > 0 {
result.TokenTTL = result.TTL
}
if result.TokenMaxTTL == 0 && result.MaxTTL > 0 {
result.TokenMaxTTL = result.MaxTTL
}
return &result, nil
}
type config struct {
tokenutil.TokenParams
OrganizationID int64 `json:"organization_id" structs:"organization_id" mapstructure:"organization_id"`
Organization string `json:"organization" structs:"organization" mapstructure:"organization"`
BaseURL string `json:"base_url" structs:"base_url" mapstructure:"base_url"`
TTL time.Duration `json:"ttl" structs:"ttl" mapstructure:"ttl"`
MaxTTL time.Duration `json:"max_ttl" structs:"max_ttl" mapstructure:"max_ttl"`
}
func (c *config) setOrganizationID(ctx context.Context, client *github.Client) error {
org, _, err := client.Organizations.Get(ctx, c.Organization)
if err != nil {
return err
}
orgID := org.GetID()
if orgID == 0 {
return fmt.Errorf("organization_id not found for %s", c.Organization)
}
c.OrganizationID = orgID
return nil
}

View File

@ -1,255 +0,0 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package github
import (
"context"
"errors"
"fmt"
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"github.com/hashicorp/vault/sdk/logical"
"github.com/stretchr/testify/assert"
)
func createBackendWithStorage(t *testing.T) (*backend, logical.Storage) {
t.Helper()
config := logical.TestBackendConfig()
config.StorageView = &logical.InmemStorage{}
b := Backend()
if b == nil {
t.Fatalf("failed to create backend")
}
err := b.Backend.Setup(context.Background(), config)
if err != nil {
t.Fatal(err)
}
return b, config.StorageView
}
// setupTestServer configures httptest server to intercept and respond to the
// request to base_url
func setupTestServer(t *testing.T) *httptest.Server {
t.Helper()
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var resp string
if strings.Contains(r.URL.String(), "/user/orgs") {
resp = string(listOrgResponse)
} else if strings.Contains(r.URL.String(), "/user/teams") {
resp = string(listUserTeamsResponse)
} else if strings.Contains(r.URL.String(), "/user") {
resp = getUserResponse
} else if strings.Contains(r.URL.String(), "/orgs/") {
resp = getOrgResponse
}
w.Header().Add("Content-Type", "application/json")
fmt.Fprintln(w, resp)
}))
}
// TestGitHub_WriteReadConfig tests that we can successfully read and write
// the github auth config
func TestGitHub_WriteReadConfig(t *testing.T) {
b, s := createBackendWithStorage(t)
// use a test server to return our mock GH org info
ts := setupTestServer(t)
defer ts.Close()
// Write the config
resp, err := b.HandleRequest(context.Background(), &logical.Request{
Path: "config",
Operation: logical.UpdateOperation,
Data: map[string]interface{}{
"organization": "foo-org",
"base_url": ts.URL, // base_url will call the test server
},
Storage: s,
})
assert.NoError(t, err)
assert.Nil(t, resp)
assert.NoError(t, resp.Error())
// Read the config
resp, err = b.HandleRequest(context.Background(), &logical.Request{
Path: "config",
Operation: logical.ReadOperation,
Storage: s,
})
assert.NoError(t, err)
assert.NoError(t, resp.Error())
// the ID should be set, we grab it from the GET /orgs API
assert.Equal(t, int64(12345), resp.Data["organization_id"])
assert.Equal(t, "foo-org", resp.Data["organization"])
}
// TestGitHub_WriteReadConfig_OrgID tests that we can successfully read and
// write the github auth config with an organization_id param
func TestGitHub_WriteReadConfig_OrgID(t *testing.T) {
b, s := createBackendWithStorage(t)
// Write the config and pass in organization_id
resp, err := b.HandleRequest(context.Background(), &logical.Request{
Path: "config",
Operation: logical.UpdateOperation,
Data: map[string]interface{}{
"organization": "foo-org",
"organization_id": 98765,
},
Storage: s,
})
assert.NoError(t, err)
assert.Nil(t, resp)
assert.NoError(t, resp.Error())
// Read the config
resp, err = b.HandleRequest(context.Background(), &logical.Request{
Path: "config",
Operation: logical.ReadOperation,
Storage: s,
})
assert.NoError(t, err)
assert.NoError(t, resp.Error())
// the ID should be set to what was written in the config
assert.Equal(t, int64(98765), resp.Data["organization_id"])
assert.Equal(t, "foo-org", resp.Data["organization"])
}
// TestGitHub_WriteReadConfig_Token tests that we can successfully read and
// write the github auth config with a token environment variable
func TestGitHub_WriteReadConfig_Token(t *testing.T) {
b, s := createBackendWithStorage(t)
// use a test server to return our mock GH org info
ts := setupTestServer(t)
defer ts.Close()
err := os.Setenv("VAULT_AUTH_CONFIG_GITHUB_TOKEN", "foobar")
assert.NoError(t, err)
resp, err := b.HandleRequest(context.Background(), &logical.Request{
Path: "config",
Operation: logical.UpdateOperation,
Data: map[string]interface{}{
"organization": "foo-org",
"base_url": ts.URL, // base_url will call the test server
},
Storage: s,
})
assert.NoError(t, err)
assert.Nil(t, resp)
assert.NoError(t, resp.Error())
// Read the config
resp, err = b.HandleRequest(context.Background(), &logical.Request{
Path: "config",
Operation: logical.ReadOperation,
Storage: s,
})
assert.NoError(t, err)
assert.NoError(t, resp.Error())
// the token should not be returned in the read config response.
assert.Nil(t, resp.Data["token"])
}
// TestGitHub_ErrorNoOrgID tests that an error is returned when we cannot fetch
// the org ID for the given org name
func TestGitHub_ErrorNoOrgID(t *testing.T) {
b, s := createBackendWithStorage(t)
// use a test server to return our mock GH org info
ts := func() *httptest.Server {
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Content-Type", "application/json")
resp := `{ "id": 0 }`
fmt.Fprintln(w, resp)
}))
}
defer ts().Close()
// Write the config
resp, err := b.HandleRequest(context.Background(), &logical.Request{
Path: "config",
Operation: logical.UpdateOperation,
Data: map[string]interface{}{
"organization": "foo-org",
"base_url": ts().URL, // base_url will call the test server
},
Storage: s,
})
assert.Error(t, err)
assert.Nil(t, resp)
assert.Equal(t, errors.New(
"unable to fetch the organization_id, you must manually set it in the config: organization_id not found for foo-org",
), err)
}
// TestGitHub_WriteConfig_ErrorNoOrg tests that an error is returned when the
// required "organization" parameter is not provided
func TestGitHub_WriteConfig_ErrorNoOrg(t *testing.T) {
b, s := createBackendWithStorage(t)
// Write the config
resp, err := b.HandleRequest(context.Background(), &logical.Request{
Path: "config",
Operation: logical.UpdateOperation,
Data: map[string]interface{}{},
Storage: s,
})
assert.NoError(t, err)
assert.Error(t, resp.Error())
assert.Equal(t, errors.New("organization is a required parameter"), resp.Error())
}
// https://docs.github.com/en/rest/reference/users#get-the-authenticated-user
// Note: many of the fields have been omitted
var getUserResponse = `
{
"login": "user-foo",
"id": 6789,
"description": "A great user. The very best user.",
"name": "foo name",
"company": "foo-company",
"type": "User"
}
`
// https://docs.github.com/en/rest/reference/orgs#get-an-organization
// Note: many of the fields have been omitted, we only care about 'login' and 'id'
var getOrgResponse = `
{
"login": "foo-org",
"id": 12345,
"description": "A great org. The very best org.",
"name": "foo-display-name",
"company": "foo-company",
"type": "Organization"
}
`
// https://docs.github.com/en/rest/reference/orgs#list-organizations-for-the-authenticated-user
var listOrgResponse = []byte(fmt.Sprintf(`[%v]`, getOrgResponse))
// https://docs.github.com/en/rest/reference/teams#list-teams-for-the-authenticated-user
// Note: many of the fields have been omitted
var listUserTeamsResponse = []byte(fmt.Sprintf(`[
{
"id": 1,
"node_id": "MDQ6VGVhbTE=",
"name": "Foo team",
"slug": "foo-team",
"description": "A great team. The very best team.",
"permission": "admin",
"organization": %v
}
]`, getOrgResponse))

View File

@ -1,312 +0,0 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package github
import (
"context"
"errors"
"fmt"
"net/url"
"github.com/google/go-github/github"
"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/cidrutil"
"github.com/hashicorp/vault/sdk/helper/policyutil"
"github.com/hashicorp/vault/sdk/logical"
)
func pathLogin(b *backend) *framework.Path {
return &framework.Path{
Pattern: "login",
DisplayAttrs: &framework.DisplayAttributes{
OperationPrefix: operationPrefixGithub,
OperationVerb: "login",
},
Fields: map[string]*framework.FieldSchema{
"token": {
Type: framework.TypeString,
Description: "GitHub personal API token",
},
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.UpdateOperation: b.pathLogin,
logical.AliasLookaheadOperation: b.pathLoginAliasLookahead,
},
}
}
func (b *backend) pathLoginAliasLookahead(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
token := data.Get("token").(string)
verifyResp, err := b.verifyCredentials(ctx, req, token)
if err != nil {
return nil, err
}
return &logical.Response{
Warnings: verifyResp.Warnings,
Auth: &logical.Auth{
Alias: &logical.Alias{
Name: *verifyResp.User.Login,
},
},
}, nil
}
func (b *backend) pathLogin(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
token := data.Get("token").(string)
verifyResp, err := b.verifyCredentials(ctx, req, token)
if err != nil {
return nil, err
}
auth := &logical.Auth{
InternalData: map[string]interface{}{
"token": token,
},
Metadata: map[string]string{
"username": *verifyResp.User.Login,
"org": *verifyResp.Org.Login,
},
DisplayName: *verifyResp.User.Login,
Alias: &logical.Alias{
Name: *verifyResp.User.Login,
},
}
verifyResp.Config.PopulateTokenAuth(auth)
// Add in configured policies from user/group mapping
if len(verifyResp.Policies) > 0 {
auth.Policies = append(auth.Policies, verifyResp.Policies...)
}
resp := &logical.Response{
Warnings: verifyResp.Warnings,
Auth: auth,
}
for _, teamName := range verifyResp.TeamNames {
if teamName == "" {
continue
}
resp.Auth.GroupAliases = append(resp.Auth.GroupAliases, &logical.Alias{
Name: teamName,
})
}
return resp, nil
}
func (b *backend) pathLoginRenew(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
if req.Auth == nil {
return nil, fmt.Errorf("request auth was nil")
}
tokenRaw, ok := req.Auth.InternalData["token"]
if !ok {
return nil, fmt.Errorf("token created in previous version of Vault cannot be validated properly at renewal time")
}
token := tokenRaw.(string)
verifyResp, err := b.verifyCredentials(ctx, req, token)
if err != nil {
return nil, err
}
if !policyutil.EquivalentPolicies(verifyResp.Policies, req.Auth.TokenPolicies) {
return nil, fmt.Errorf("policies do not match")
}
resp := &logical.Response{Auth: req.Auth}
resp.Auth.Period = verifyResp.Config.TokenPeriod
resp.Auth.TTL = verifyResp.Config.TokenTTL
resp.Auth.MaxTTL = verifyResp.Config.TokenMaxTTL
resp.Warnings = verifyResp.Warnings
// Remove old aliases
resp.Auth.GroupAliases = nil
for _, teamName := range verifyResp.TeamNames {
resp.Auth.GroupAliases = append(resp.Auth.GroupAliases, &logical.Alias{
Name: teamName,
})
}
return resp, nil
}
func (b *backend) verifyCredentials(ctx context.Context, req *logical.Request, token string) (*verifyCredentialsResp, error) {
var warnings []string
config, err := b.Config(ctx, req.Storage)
if err != nil {
return nil, err
}
if config == nil {
return nil, errors.New("configuration has not been set")
}
// Check for a CIDR match.
if len(config.TokenBoundCIDRs) > 0 {
if req.Connection == nil {
b.Logger().Error("token bound CIDRs found but no connection information available for validation")
return nil, logical.ErrPermissionDenied
}
if !cidrutil.RemoteAddrIsOk(req.Connection.RemoteAddr, config.TokenBoundCIDRs) {
return nil, logical.ErrPermissionDenied
}
}
client, err := b.Client(token)
if err != nil {
return nil, err
}
if config.BaseURL != "" {
parsedURL, err := url.Parse(config.BaseURL)
if err != nil {
return nil, fmt.Errorf("successfully parsed base_url when set but failing to parse now: %w", err)
}
client.BaseURL = parsedURL
}
if config.OrganizationID == 0 {
// Previously we did not verify using the Org ID. So if the Org ID is
// not set, we will trust-on-first-use and set it now.
err = config.setOrganizationID(ctx, client)
if err != nil {
b.Logger().Error("failed to set the organization_id on login", "error", err)
return nil, err
}
entry, err := logical.StorageEntryJSON("config", config)
if err != nil {
return nil, err
}
if err := req.Storage.Put(ctx, entry); err != nil {
return nil, err
}
b.Logger().Info("set ID on a trust-on-first-use basis", "organization_id", config.OrganizationID)
}
// Get the user
user, _, err := client.Users.Get(ctx, "")
if err != nil {
return nil, err
}
// Verify that the user is part of the organization
var org *github.Organization
orgOpt := &github.ListOptions{
PerPage: 100,
}
var allOrgs []*github.Organization
for {
orgs, resp, err := client.Organizations.List(ctx, "", orgOpt)
if err != nil {
return nil, err
}
allOrgs = append(allOrgs, orgs...)
if resp.NextPage == 0 {
break
}
orgOpt.Page = resp.NextPage
}
orgLoginName := ""
for _, o := range allOrgs {
if o.GetID() == config.OrganizationID {
org = o
orgLoginName = *o.Login
break
}
}
if org == nil {
return nil, errors.New("user is not part of required org")
}
if orgLoginName != config.Organization {
warningMsg := fmt.Sprintf(
"the organization name has changed to %q. It is recommended to verify and update the organization name in the config: %s=%d",
orgLoginName,
"organization_id",
config.OrganizationID,
)
b.Logger().Warn(warningMsg)
warnings = append(warnings, warningMsg)
}
// Get the teams that this user is part of to determine the policies
var teamNames []string
teamOpt := &github.ListOptions{
PerPage: 100,
}
var allTeams []*github.Team
for {
teams, resp, err := client.Teams.ListUserTeams(ctx, teamOpt)
if err != nil {
return nil, err
}
allTeams = append(allTeams, teams...)
if resp.NextPage == 0 {
break
}
teamOpt.Page = resp.NextPage
}
for _, t := range allTeams {
// We only care about teams that are part of the organization we use
if *t.Organization.ID != *org.ID {
continue
}
// Append the names so we can get the policies
teamNames = append(teamNames, *t.Name)
if *t.Name != *t.Slug {
teamNames = append(teamNames, *t.Slug)
}
}
groupPoliciesList, err := b.TeamMap.Policies(ctx, req.Storage, teamNames...)
if err != nil {
return nil, err
}
userPoliciesList, err := b.UserMap.Policies(ctx, req.Storage, []string{*user.Login}...)
if err != nil {
return nil, err
}
verifyResp := &verifyCredentialsResp{
User: user,
Org: org,
Policies: append(groupPoliciesList, userPoliciesList...),
TeamNames: teamNames,
Config: config,
Warnings: warnings,
}
return verifyResp, nil
}
type verifyCredentialsResp struct {
User *github.User
Org *github.Organization
Policies []string
TeamNames []string
// Warnings to send back to the caller
Warnings []string
// This is just a cache to send back to the caller
Config *config
}

View File

@ -1,189 +0,0 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package github
import (
"context"
"errors"
"testing"
"github.com/hashicorp/vault/helper/namespace"
"github.com/hashicorp/vault/sdk/logical"
"github.com/stretchr/testify/assert"
)
// TestGitHub_Login tests that we can successfully login with the given config
func TestGitHub_Login(t *testing.T) {
b, s := createBackendWithStorage(t)
// use a test server to return our mock GH org info
ts := setupTestServer(t)
defer ts.Close()
// Write the config
resp, err := b.HandleRequest(context.Background(), &logical.Request{
Path: "config",
Operation: logical.UpdateOperation,
Data: map[string]interface{}{
"organization": "foo-org",
"base_url": ts.URL, // base_url will call the test server
},
Storage: s,
})
assert.NoError(t, err)
assert.NoError(t, resp.Error())
// Read the config
resp, err = b.HandleRequest(context.Background(), &logical.Request{
Path: "config",
Operation: logical.ReadOperation,
Storage: s,
})
assert.NoError(t, err)
assert.NoError(t, resp.Error())
// attempt a login
resp, err = b.HandleRequest(context.Background(), &logical.Request{
Path: "login",
Operation: logical.UpdateOperation,
Storage: s,
})
expectedMetaData := map[string]string{
"org": "foo-org",
"username": "user-foo",
}
assert.Equal(t, expectedMetaData, resp.Auth.Metadata)
assert.NoError(t, err)
assert.NoError(t, resp.Error())
}
// TestGitHub_Login_OrgInvalid tests that we cannot login with an ID other than
// what is set in the config
func TestGitHub_Login_OrgInvalid(t *testing.T) {
b, s := createBackendWithStorage(t)
ctx := namespace.RootContext(nil)
// use a test server to return our mock GH org info
ts := setupTestServer(t)
defer ts.Close()
// write and store config
config := config{
Organization: "foo-org",
OrganizationID: 9999,
BaseURL: ts.URL + "/", // base_url will call the test server
}
entry, err := logical.StorageEntryJSON("config", config)
if err != nil {
t.Fatalf("failed creating storage entry")
}
if err := s.Put(ctx, entry); err != nil {
t.Fatalf("writing to in mem storage failed")
}
// attempt a login
resp, err := b.HandleRequest(context.Background(), &logical.Request{
Path: "login",
Operation: logical.UpdateOperation,
Storage: s,
})
assert.Nil(t, resp)
assert.Error(t, err)
assert.Equal(t, errors.New("user is not part of required org"), err)
}
// TestGitHub_Login_OrgNameChanged tests that we can successfully login with the
// given config and emit a warning when the organization name has changed
func TestGitHub_Login_OrgNameChanged(t *testing.T) {
b, s := createBackendWithStorage(t)
ctx := namespace.RootContext(nil)
// use a test server to return our mock GH org info
ts := setupTestServer(t)
defer ts.Close()
// write and store config
// the name does not match what the API will return but the ID does
config := config{
Organization: "old-name",
OrganizationID: 12345,
BaseURL: ts.URL + "/", // base_url will call the test server
}
entry, err := logical.StorageEntryJSON("config", config)
if err != nil {
t.Fatalf("failed creating storage entry")
}
if err := s.Put(ctx, entry); err != nil {
t.Fatalf("writing to in mem storage failed")
}
// attempt a login
resp, err := b.HandleRequest(context.Background(), &logical.Request{
Path: "login",
Operation: logical.UpdateOperation,
Storage: s,
})
assert.NoError(t, err)
assert.Nil(t, resp.Error())
assert.Equal(
t,
[]string{"the organization name has changed to \"foo-org\". It is recommended to verify and update the organization name in the config: organization_id=12345"},
resp.Warnings,
)
}
// TestGitHub_Login_NoOrgID tests that we can successfully login with the given
// config when no organization ID is present and write the fetched ID to the
// config
func TestGitHub_Login_NoOrgID(t *testing.T) {
b, s := createBackendWithStorage(t)
ctx := namespace.RootContext(nil)
// use a test server to return our mock GH org info
ts := setupTestServer(t)
defer ts.Close()
// write and store config without Org ID
config := config{
Organization: "foo-org",
BaseURL: ts.URL + "/", // base_url will call the test server
}
entry, err := logical.StorageEntryJSON("config", config)
if err != nil {
t.Fatalf("failed creating storage entry")
}
if err := s.Put(ctx, entry); err != nil {
t.Fatalf("writing to in mem storage failed")
}
// attempt a login
resp, err := b.HandleRequest(context.Background(), &logical.Request{
Path: "login",
Operation: logical.UpdateOperation,
Storage: s,
})
expectedMetaData := map[string]string{
"org": "foo-org",
"username": "user-foo",
}
assert.Equal(t, expectedMetaData, resp.Auth.Metadata)
assert.NoError(t, err)
assert.NoError(t, resp.Error())
// Read the config
resp, err = b.HandleRequest(context.Background(), &logical.Request{
Path: "config",
Operation: logical.ReadOperation,
Storage: s,
})
assert.NoError(t, err)
assert.NoError(t, resp.Error())
// the ID should be set, we grab it from the GET /orgs API
assert.Equal(t, int64(12345), resp.Data["organization_id"])
}

View File

@ -105,7 +105,6 @@ func (b *BaseCommand) PredictVaultAvailableAuths() complete.Predictor {
"app-id", "app-id",
"approle", "approle",
"cert", "cert",
"github",
"ldap", "ldap",
"plugin", "plugin",
"radius", "radius",

View File

@ -29,7 +29,6 @@ import (
credOIDC "github.com/hashicorp/vault-plugin-auth-jwt" credOIDC "github.com/hashicorp/vault-plugin-auth-jwt"
credKerb "github.com/hashicorp/vault-plugin-auth-kerberos" credKerb "github.com/hashicorp/vault-plugin-auth-kerberos"
credCert "github.com/hashicorp/vault/builtin/credential/cert" credCert "github.com/hashicorp/vault/builtin/credential/cert"
credGitHub "github.com/hashicorp/vault/builtin/credential/github"
credLdap "github.com/hashicorp/vault/builtin/credential/ldap" credLdap "github.com/hashicorp/vault/builtin/credential/ldap"
credToken "github.com/hashicorp/vault/builtin/credential/token" credToken "github.com/hashicorp/vault/builtin/credential/token"
credUserpass "github.com/hashicorp/vault/builtin/credential/userpass" credUserpass "github.com/hashicorp/vault/builtin/credential/userpass"
@ -178,7 +177,6 @@ var (
func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) map[string]cli.CommandFactory { func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) map[string]cli.CommandFactory {
loginHandlers := map[string]LoginHandler{ loginHandlers := map[string]LoginHandler{
"cert": &credCert.CLIHandler{}, "cert": &credCert.CLIHandler{},
"github": &credGitHub.CLIHandler{},
"kerberos": &credKerb.CLIHandler{}, "kerberos": &credKerb.CLIHandler{},
"ldap": &credLdap.CLIHandler{}, "ldap": &credLdap.CLIHandler{},
"oidc": &credOIDC.CLIHandler{}, "oidc": &credOIDC.CLIHandler{},

3
go.mod
View File

@ -45,7 +45,6 @@ require (
github.com/gocql/gocql v1.0.0 github.com/gocql/gocql v1.0.0
github.com/golang/protobuf v1.5.3 github.com/golang/protobuf v1.5.3
github.com/google/go-cmp v0.6.0 github.com/google/go-cmp v0.6.0
github.com/google/go-github v17.0.0+incompatible
github.com/google/tink/go v1.7.0 github.com/google/tink/go v1.7.0
github.com/hashicorp-forge/bbolt v1.3.8-hc3 github.com/hashicorp-forge/bbolt v1.3.8-hc3
github.com/hashicorp/cap v0.3.0 github.com/hashicorp/cap v0.3.0
@ -155,7 +154,6 @@ require (
golang.org/x/crypto v0.23.0 golang.org/x/crypto v0.23.0
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 golang.org/x/exp v0.0.0-20240222234643-814bf88cf225
golang.org/x/net v0.25.0 golang.org/x/net v0.25.0
golang.org/x/oauth2 v0.18.0
golang.org/x/sync v0.7.0 golang.org/x/sync v0.7.0
golang.org/x/sys v0.20.0 golang.org/x/sys v0.20.0
golang.org/x/term v0.20.0 golang.org/x/term v0.20.0
@ -341,6 +339,7 @@ require (
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect
go.opentelemetry.io/otel/metric v1.22.0 // indirect go.opentelemetry.io/otel/metric v1.22.0 // indirect
golang.org/x/mod v0.15.0 // indirect golang.org/x/mod v0.15.0 // indirect
golang.org/x/oauth2 v0.18.0 // indirect
golang.org/x/time v0.5.0 // indirect golang.org/x/time v0.5.0 // indirect
google.golang.org/api v0.163.0 // indirect google.golang.org/api v0.163.0 // indirect
google.golang.org/appengine v1.6.8 // indirect google.golang.org/appengine v1.6.8 // indirect

2
go.sum
View File

@ -1713,8 +1713,6 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0= github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0=
github.com/google/go-containerregistry v0.14.0/go.mod h1:aiJ2fp/SXvkWgmYHioXnbMdlgB8eXiiYOY55gfN91Wk= github.com/google/go-containerregistry v0.14.0/go.mod h1:aiJ2fp/SXvkWgmYHioXnbMdlgB8eXiiYOY55gfN91Wk=
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=

View File

@ -16,7 +16,6 @@ import (
logicalTerraform "github.com/hashicorp/vault-plugin-secrets-terraform" logicalTerraform "github.com/hashicorp/vault-plugin-secrets-terraform"
credAppRole "github.com/hashicorp/vault/builtin/credential/approle" credAppRole "github.com/hashicorp/vault/builtin/credential/approle"
credCert "github.com/hashicorp/vault/builtin/credential/cert" credCert "github.com/hashicorp/vault/builtin/credential/cert"
credGitHub "github.com/hashicorp/vault/builtin/credential/github"
credLdap "github.com/hashicorp/vault/builtin/credential/ldap" credLdap "github.com/hashicorp/vault/builtin/credential/ldap"
credRadius "github.com/hashicorp/vault/builtin/credential/radius" credRadius "github.com/hashicorp/vault/builtin/credential/radius"
credUserpass "github.com/hashicorp/vault/builtin/credential/userpass" credUserpass "github.com/hashicorp/vault/builtin/credential/userpass"
@ -80,7 +79,6 @@ func newRegistry() *registry {
}, },
"approle": {Factory: credAppRole.Factory}, "approle": {Factory: credAppRole.Factory},
"cert": {Factory: credCert.Factory}, "cert": {Factory: credCert.Factory},
"github": {Factory: credGitHub.Factory},
"jwt": {Factory: credJWT.Factory}, "jwt": {Factory: credJWT.Factory},
"kerberos": {Factory: credKerb.Factory}, "kerberos": {Factory: credKerb.Factory},
"kubernetes": {Factory: credKube.Factory}, "kubernetes": {Factory: credKube.Factory},

View File

@ -52,7 +52,6 @@ echo "Mounting all builtin plugins ..."
# Enable auth plugins # Enable auth plugins
vault auth enable "approle" vault auth enable "approle"
vault auth enable "cert" vault auth enable "cert"
vault auth enable "github"
vault auth enable "jwt" vault auth enable "jwt"
vault auth enable "kerberos" vault auth enable "kerberos"
vault auth enable "kubernetes" vault auth enable "kubernetes"

View File

@ -1,8 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import AuthConfig from './_base';
export default AuthConfig.extend();

View File

@ -18,13 +18,6 @@ const MOUNTABLE_AUTH_METHODS = [
type: 'approle', type: 'approle',
category: 'generic', category: 'generic',
}, },
{
displayName: 'GitHub',
value: 'github',
type: 'github',
category: 'cloud',
glyph: 'github-color',
},
{ {
displayName: 'JWT', displayName: 'JWT',
value: 'jwt', value: 'jwt',

View File

@ -60,14 +60,6 @@ const SUPPORTED_AUTH_BACKENDS = [
displayNamePath: 'metadata.username', displayNamePath: 'metadata.username',
formAttributes: ['username', 'password'], formAttributes: ['username', 'password'],
}, },
{
type: 'github',
typeDisplay: 'GitHub',
description: 'GitHub authentication.',
tokenPath: 'client_token',
displayNamePath: ['metadata.org', 'metadata.username'],
formAttributes: ['token'],
},
]; ];
export function supportedAuthBackends() { export function supportedAuthBackends() {

View File

@ -1,32 +0,0 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: BUSL-1.1
*/
import { attr } from '@ember-data/model';
import { computed } from '@ember/object';
import AuthConfig from '../auth-config';
import fieldToAttrs from 'vault/utils/field-to-attrs';
import { combineFieldGroups } from 'vault/utils/openapi-to-attrs';
export default AuthConfig.extend({
useOpenAPI: true,
organization: attr('string'),
baseUrl: attr('string', {
label: 'Base URL',
}),
fieldGroups: computed('newFields', function () {
let groups = [
{ default: ['organization'] },
{
'GitHub Options': ['baseUrl'],
},
];
if (this.newFields) {
groups = combineFieldGroups(groups, this.newFields, []);
}
return fieldToAttrs(this, groups);
}),
});

View File

@ -17,7 +17,6 @@ export default Route.extend(UnloadModelRoute, {
modelType(backendType, section) { modelType(backendType, section) {
const MODELS = { const MODELS = {
'github-configuration': 'auth-config/github',
'jwt-configuration': 'auth-config/jwt', 'jwt-configuration': 'auth-config/jwt',
'oidc-configuration': 'auth-config/oidc', 'oidc-configuration': 'auth-config/oidc',
'kubernetes-configuration': 'auth-config/kubernetes', 'kubernetes-configuration': 'auth-config/kubernetes',

View File

@ -87,23 +87,7 @@
</AuthJwt> </AuthJwt>
{{else}} {{else}}
<form id="auth-form" onsubmit={{action "doSubmit" null}}> <form id="auth-form" onsubmit={{action "doSubmit" null}}>
{{#if (eq this.providerName "github")}} {{if (eq this.providerName "token")}}
<div class="field">
<label for="token" class="is-label">GitHub token</label>
<div class="control">
<Input
@type="password"
@value={{this.token}}
name="token"
id="token"
class="input"
data-test-token={{true}}
autocomplete="off"
spellcheck="false"
/>
</div>
</div>
{{else if (eq this.providerName "token")}}
<div class="field"> <div class="field">
<label for="token" class="is-label">Token</label> <label for="token" class="is-label">Token</label>
<div class="control"> <div class="control">

View File

@ -1,15 +0,0 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: BUSL-1.1
~}}
<WizardSection
@headerText="GitHub"
@headerIcon="github"
@docText="Docs: GitHub Authentication"
@docPath="/docs/auth/github.html"
>
<p>
The Github Auth Method can be used to authenticate with Vault using a GitHub personal access token.
</p>
</WizardSection>

View File

@ -125,8 +125,6 @@ export const structureIconMap = {
'logo-bitbucket-monochrome': 'bitbucket', 'logo-bitbucket-monochrome': 'bitbucket',
'logo-f5-color': 'f5-color', 'logo-f5-color': 'f5-color',
'logo-f5-monochrome': 'f5', 'logo-f5-monochrome': 'f5',
'logo-github-color': 'github-color',
'logo-github-monochrome': 'github',
'logo-gitlab-color': 'gitlab-color', 'logo-gitlab-color': 'gitlab-color',
'logo-gitlab-monochrome': 'gitlab', 'logo-gitlab-monochrome': 'gitlab',
'logo-google-color': 'google-color', 'logo-google-color': 'google-color',

View File

@ -1 +0,0 @@
<svg viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg"><path d="M24 4c11.045 0 20 8.954 20 20 0 8.834-5.723 16.328-13.666 18.976-1.014.196-1.374-.428-1.374-.96 0-.659.024-2.812.024-5.488 0-1.866-.64-3.083-1.357-3.704 4.454-.495 9.132-2.187 9.132-9.868 0-2.184-.776-3.968-2.058-5.369.208-.503.893-2.538-.196-5.293 0 0-1.677-.537-5.495 2.05a19.22 19.22 0 0 0-5.01-.672c-1.7.007-3.41.23-5.006.673-3.822-2.588-5.501-2.05-5.501-2.05-1.086 2.754-.402 4.789-.194 5.292-1.28 1.4-2.06 3.185-2.06 5.369 0 7.663 4.67 9.378 9.111 9.884-.572.5-1.09 1.381-1.27 2.674-1.14.511-4.036 1.395-5.82-1.662 0 0-1.057-1.92-3.065-2.061 0 0-1.952-.026-.137 1.215 0 0 1.31.615 2.22 2.927 0 0 1.175 3.57 6.739 2.36.008 1.67.027 3.246.027 3.723 0 .528-.367 1.147-1.367.962C9.731 40.334 4 32.837 4 24 4 12.954 12.956 4 24 4zM11.575 32.716c-.044.1-.2.129-.343.06-.145-.064-.226-.2-.18-.3.044-.102.2-.13.345-.062.146.065.228.202.178.302zm.81.903c-.095.089-.282.048-.408-.092-.131-.14-.156-.326-.059-.416.099-.088.28-.047.41.093.131.14.157.326.057.415zm.789 1.152c-.123.085-.323.006-.447-.172-.123-.178-.123-.391.003-.477.124-.085.321-.008.447.168.122.18.122.394-.003.481zm1.08 1.113c-.11.121-.343.089-.514-.076-.175-.162-.223-.39-.114-.511.111-.122.346-.088.518.076.174.161.227.392.11.511zm1.49.646c-.048.157-.273.228-.5.162-.225-.069-.374-.253-.328-.41.047-.158.273-.233.501-.161.226.068.375.25.327.41zm1.637.12c.006.165-.186.302-.424.305-.24.005-.433-.128-.435-.29 0-.167.188-.303.427-.307.238-.004.432.128.432.292zm1.523-.26c.029.162-.136.327-.373.371-.232.042-.447-.057-.476-.217-.029-.164.14-.33.371-.372.237-.042.448.055.478.219z" fill="#161514" fill-rule="evenodd"/></svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB