mirror of
https://github.com/coder/coder.git
synced 2025-07-08 11:39:50 +00:00
This allows template authors to leverage git auth to perform custom actions, like clone repositories.
200 lines
5.4 KiB
Go
200 lines
5.4 KiB
Go
package gitauth_test
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"golang.org/x/oauth2"
|
|
"golang.org/x/xerrors"
|
|
|
|
"github.com/coder/coder/coderd/database"
|
|
"github.com/coder/coder/coderd/database/dbfake"
|
|
"github.com/coder/coder/coderd/database/dbgen"
|
|
"github.com/coder/coder/coderd/gitauth"
|
|
"github.com/coder/coder/codersdk"
|
|
"github.com/coder/coder/testutil"
|
|
)
|
|
|
|
func TestRefreshToken(t *testing.T) {
|
|
t.Parallel()
|
|
t.Run("FalseIfNoRefresh", func(t *testing.T) {
|
|
t.Parallel()
|
|
config := &gitauth.Config{
|
|
NoRefresh: true,
|
|
}
|
|
_, refreshed, err := config.RefreshToken(context.Background(), nil, database.GitAuthLink{
|
|
OAuthExpiry: time.Time{},
|
|
})
|
|
require.NoError(t, err)
|
|
require.False(t, refreshed)
|
|
})
|
|
t.Run("FalseIfTokenSourceFails", func(t *testing.T) {
|
|
t.Parallel()
|
|
config := &gitauth.Config{
|
|
OAuth2Config: &testutil.OAuth2Config{
|
|
TokenSourceFunc: func() (*oauth2.Token, error) {
|
|
return nil, xerrors.New("failure")
|
|
},
|
|
},
|
|
}
|
|
_, refreshed, err := config.RefreshToken(context.Background(), nil, database.GitAuthLink{})
|
|
require.NoError(t, err)
|
|
require.False(t, refreshed)
|
|
})
|
|
t.Run("ValidateServerError", func(t *testing.T) {
|
|
t.Parallel()
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
w.Write([]byte("Failure"))
|
|
}))
|
|
config := &gitauth.Config{
|
|
OAuth2Config: &testutil.OAuth2Config{},
|
|
ValidateURL: srv.URL,
|
|
}
|
|
_, _, err := config.RefreshToken(context.Background(), nil, database.GitAuthLink{})
|
|
require.ErrorContains(t, err, "Failure")
|
|
})
|
|
t.Run("ValidateFailure", func(t *testing.T) {
|
|
t.Parallel()
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
w.Write([]byte("Not permitted"))
|
|
}))
|
|
config := &gitauth.Config{
|
|
OAuth2Config: &testutil.OAuth2Config{},
|
|
ValidateURL: srv.URL,
|
|
}
|
|
_, refreshed, err := config.RefreshToken(context.Background(), nil, database.GitAuthLink{})
|
|
require.NoError(t, err)
|
|
require.False(t, refreshed)
|
|
})
|
|
t.Run("ValidateNoUpdate", func(t *testing.T) {
|
|
t.Parallel()
|
|
validated := make(chan struct{})
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
close(validated)
|
|
}))
|
|
accessToken := "testing"
|
|
config := &gitauth.Config{
|
|
OAuth2Config: &testutil.OAuth2Config{
|
|
Token: &oauth2.Token{
|
|
AccessToken: accessToken,
|
|
},
|
|
},
|
|
ValidateURL: srv.URL,
|
|
}
|
|
_, valid, err := config.RefreshToken(context.Background(), nil, database.GitAuthLink{
|
|
OAuthAccessToken: accessToken,
|
|
})
|
|
require.NoError(t, err)
|
|
require.True(t, valid)
|
|
<-validated
|
|
})
|
|
t.Run("Updates", func(t *testing.T) {
|
|
t.Parallel()
|
|
config := &gitauth.Config{
|
|
ID: "test",
|
|
OAuth2Config: &testutil.OAuth2Config{
|
|
Token: &oauth2.Token{
|
|
AccessToken: "updated",
|
|
},
|
|
},
|
|
}
|
|
db := dbfake.New()
|
|
link := dbgen.GitAuthLink(t, db, database.GitAuthLink{
|
|
ProviderID: config.ID,
|
|
OAuthAccessToken: "initial",
|
|
})
|
|
_, valid, err := config.RefreshToken(context.Background(), db, link)
|
|
require.NoError(t, err)
|
|
require.True(t, valid)
|
|
})
|
|
}
|
|
|
|
func TestConvertYAML(t *testing.T) {
|
|
t.Parallel()
|
|
for _, tc := range []struct {
|
|
Name string
|
|
Input []codersdk.GitAuthConfig
|
|
Output []*gitauth.Config
|
|
Error string
|
|
}{{
|
|
Name: "InvalidType",
|
|
Input: []codersdk.GitAuthConfig{{
|
|
Type: "moo",
|
|
}},
|
|
Error: "unknown git provider type",
|
|
}, {
|
|
Name: "InvalidID",
|
|
Input: []codersdk.GitAuthConfig{{
|
|
Type: string(codersdk.GitProviderGitHub),
|
|
ID: "$hi$",
|
|
}},
|
|
Error: "doesn't have a valid id",
|
|
}, {
|
|
Name: "NoClientID",
|
|
Input: []codersdk.GitAuthConfig{{
|
|
Type: string(codersdk.GitProviderGitHub),
|
|
}},
|
|
Error: "client_id must be provided",
|
|
}, {
|
|
Name: "NoClientSecret",
|
|
Input: []codersdk.GitAuthConfig{{
|
|
Type: string(codersdk.GitProviderGitHub),
|
|
ClientID: "example",
|
|
}},
|
|
Error: "client_secret must be provided",
|
|
}, {
|
|
Name: "DuplicateType",
|
|
Input: []codersdk.GitAuthConfig{{
|
|
Type: string(codersdk.GitProviderGitHub),
|
|
ClientID: "example",
|
|
ClientSecret: "example",
|
|
}, {
|
|
Type: string(codersdk.GitProviderGitHub),
|
|
}},
|
|
Error: "multiple github git auth providers provided",
|
|
}, {
|
|
Name: "InvalidRegex",
|
|
Input: []codersdk.GitAuthConfig{{
|
|
Type: string(codersdk.GitProviderGitHub),
|
|
ClientID: "example",
|
|
ClientSecret: "example",
|
|
Regex: `\K`,
|
|
}},
|
|
Error: "compile regex for git auth provider",
|
|
}} {
|
|
tc := tc
|
|
t.Run(tc.Name, func(t *testing.T) {
|
|
t.Parallel()
|
|
output, err := gitauth.ConvertConfig(tc.Input, &url.URL{})
|
|
if tc.Error != "" {
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), tc.Error)
|
|
return
|
|
}
|
|
require.Equal(t, tc.Output, output)
|
|
})
|
|
}
|
|
|
|
t.Run("CustomScopesAndEndpoint", func(t *testing.T) {
|
|
t.Parallel()
|
|
config, err := gitauth.ConvertConfig([]codersdk.GitAuthConfig{{
|
|
Type: string(codersdk.GitProviderGitLab),
|
|
ClientID: "id",
|
|
ClientSecret: "secret",
|
|
AuthURL: "https://auth.com",
|
|
TokenURL: "https://token.com",
|
|
Scopes: []string{"read"},
|
|
}}, &url.URL{})
|
|
require.NoError(t, err)
|
|
require.Equal(t, "https://auth.com?client_id=id&redirect_uri=%2Fgitauth%2Fgitlab%2Fcallback&response_type=code&scope=read", config[0].AuthCodeURL(""))
|
|
})
|
|
}
|