Merge branch 'master' into feature/static_password_env

This commit is contained in:
Krishna Durai
2020-01-06 23:21:20 -08:00
committed by GitHub
46 changed files with 897 additions and 279 deletions
+2 -2
View File
@@ -69,8 +69,8 @@ jobs:
DEX_KEYSTONE_ADMIN_USER: demo
DEX_KEYSTONE_ADMIN_PASS: DEMO_PASS
- name: Run Kubernetes tests
run: ./scripts/test-k8s.sh
- name: Run linter
run: make lint
# Ensure proto generation doesn't depend on external packages.
- name: Verify proto
+35
View File
@@ -0,0 +1,35 @@
run:
skip-dirs:
- vendor
linters-settings:
golint:
min-confidence: 0.1
goimports:
local-prefixes: github.com/dexidp/dex
linters:
enable-all: true
disable:
- funlen
- maligned
- wsl
# TODO: fix me
- unparam
- golint
- goconst
- staticcheck
- nakedret
- errcheck
- gosec
- gochecknoinits
- gochecknoglobals
- prealloc
- scopelint
- lll
- dupl
- gocritic
- gocyclo
- gocognit
- godox
-1
View File
@@ -48,7 +48,6 @@ install:
script:
- make testall
- ./scripts/test-k8s.sh
- make verify-proto # Ensure proto generation doesn't depend on external packages.
notifications:
+79
View File
@@ -0,0 +1,79 @@
# Authentication using OpenShift
## Overview
Dex can make use of users and groups defined within OpenShift by querying the platform provided OAuth server.
## Configuration
### Creating an OAuth Client
Two forms of OAuth Clients can be utilized:
* [Using a Service Account as an OAuth Client](https://docs.openshift.com/container-platform/latest/authentication/using-service-accounts-as-oauth-client.html) (Recommended)
* [Registering An Additional OAuth Client](https://docs.openshift.com/container-platform/latest/authentication/configuring-internal-oauth.html#oauth-register-additional-client_configuring-internal-oauth)
#### Using a Service Account as an OAuth Client
OpenShift Service Accounts can be used as a constrained form of OAuth client. Making use of a Service Account to represent an OAuth Client is the recommended option as it does not require elevated privileged within the OpenShift cluster. Create a new Service Account or make use of an existing Service Account.
Patch the Service Account to add an annotation for location of the Redirect URI
```
oc patch serviceaccount <name> --type='json' -p='[{"op": "add", "path": "/metadata/annotations/serviceaccounts.openshift.io~1oauth-redirecturi.dex", "value":"https:///<dex_url>/callback"}]'
```
The Client ID for a Service Account representing an OAuth Client takes the form `
The Client Secret for a Service Account representing an OAuth Client is the long lived OAuth Token that is configued for the Service Account. Execute the following command to retrieve the OAuth Token.
```
oc serviceaccounts get-token <name>
```
#### Registering An Additional OAuth Client
Instead of using a constrained form of Service Account to represent an OAuth Client, an additional OAuthClient resource can be created.
Create a new OAuthClient resource similar to the following:
```yaml
kind: OAuthClient
apiVersion: oauth.openshift.io/v1
metadata:
name: dex
# The value that should be utilized as the `client_secret`
secret: "<clientSecret>"
# List of valid addresses for the callback. Ensure one of the values that are provided is `(dex issuer)/callback`
redirectURIs:
- "https:///<dex_url>/callback"
grantMethod: prompt
```
### Dex Configuration
The following is an example of a configuration for `examples/config-dev.yaml`:
```yaml
connectors:
- type: openshift
# Required field for connector id.
id: openshift
# Required field for connector name.
name: OpenShift
config:
# OpenShift API
issuer: https://api.mycluster.example.com:6443
# Credentials can be string literals or pulled from the environment.
clientID: $OPENSHIFT_OAUTH_CLIENT_ID
clientSecret: $OPENSHIFT_OAUTH_CLIENT_SECRET
redirectURI: http://127.0.0.1:5556/dex/
# Optional: Specify whether to communicate to OpenShift without validating SSL ceertificates
insecureCA: false
# Optional: The location of file containing SSL certificates to commmunicate to OpenShift
rootCA: /etc/ssl/openshift.pem
# Optional list of required groups a user mmust be a member of
groups:
- users
```
-16
View File
@@ -1,21 +1,5 @@
# Running integration tests
## Kubernetes
Kubernetes tests run against a Kubernetes API server, and are enabled by the `DEX_KUBECONFIG` environment variable:
```
$ export DEX_KUBECONFIG=~/.kube/config
$ go test -v -i ./storage/kubernetes
$ go test -v ./storage/kubernetes
```
These tests can be executed locally using docker by running the following script:
```
$ ./scripts/test-k8s.sh
```
## Postgres
Running database tests locally requires:
+2
View File
@@ -14,11 +14,13 @@ Steps:
```yaml
frontend:
dir: /path/to/custom/web
issuer: my-dex
extra:
tos_footer_link: "https://example.com/terms"
client_logo_url: "../theme/client-logo.png"
foo: "bar"
```
5. Set the `frontend.dir` value to your own `web` directory.
6. Write the issuer in the `issuer` directory in order to modify the Dex title and the `Log in to <<dex>>` tag.
To test your templates simply run Dex with a valid configuration and go through a login flow.
+31 -14
View File
@@ -2,7 +2,6 @@ PROJ=dex
ORG_PATH=github.com/dexidp
REPO_PATH=$(ORG_PATH)/$(PROJ)
export PATH := $(PWD)/bin:$(PATH)
THIS_DIRECTORY:=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
VERSION ?= $(shell ./scripts/git-version)
@@ -18,6 +17,9 @@ export GOBIN=$(PWD)/bin
LD_FLAGS="-w -X $(REPO_PATH)/version.Version=$(VERSION)"
# Dependency versions
GOLANGCI_VERSION = 1.21.0
build: bin/dex bin/example-app bin/grpc-client
bin/dex:
@@ -39,20 +41,38 @@ revendor:
@go mod vendor -v
@go mod verify
test:
test: bin/test/kube-apiserver bin/test/etcd
@go test -v ./...
testrace:
testrace: bin/test/kube-apiserver bin/test/etcd
@go test -v --race ./...
vet:
@go vet ./...
export TEST_ASSET_KUBE_APISERVER=$(abspath bin/test/kube-apiserver)
export TEST_ASSET_ETCD=$(abspath bin/test/etcd)
fmt:
@./scripts/gofmt ./...
bin/test/kube-apiserver:
@mkdir -p bin/test
curl -L https://storage.googleapis.com/k8s-c10s-test-binaries/kube-apiserver-$(shell uname)-x86_64 > bin/test/kube-apiserver
chmod +x bin/test/kube-apiserver
lint: bin/golint
@./bin/golint -set_exit_status $(shell go list ./...)
bin/test/etcd:
@mkdir -p bin/test
curl -L https://storage.googleapis.com/k8s-c10s-test-binaries/etcd-$(shell uname)-x86_64 > bin/test/etcd
chmod +x bin/test/etcd
bin/golangci-lint: bin/golangci-lint-${GOLANGCI_VERSION}
@ln -sf golangci-lint-${GOLANGCI_VERSION} bin/golangci-lint
bin/golangci-lint-${GOLANGCI_VERSION}:
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | BINARY=golangci-lint bash -s -- v${GOLANGCI_VERSION}
@mv bin/golangci-lint $@
.PHONY: lint
lint: bin/golangci-lint ## Run linter
bin/golangci-lint run
.PHONY: fix
fix: bin/golangci-lint ## Fix lint violations
bin/golangci-lint run --fix
.PHONY: docker-image
docker-image:
@@ -73,14 +93,11 @@ bin/protoc: scripts/get-protoc
bin/protoc-gen-go:
@go install -v $(REPO_PATH)/vendor/github.com/golang/protobuf/protoc-gen-go
bin/golint:
@go install -v $(THIS_DIRECTORY)/vendor/golang.org/x/lint/golint
clean:
@rm -rf bin/
testall: testrace vet fmt lint
testall: testrace
FORCE:
.PHONY: test testrace vet fmt lint testall
.PHONY: test testrace testall
+1
View File
@@ -74,6 +74,7 @@ Dex implements the following connectors:
| [Microsoft](Documentation/connectors/microsoft.md) | yes | yes | no | beta | |
| [AuthProxy](Documentation/connectors/authproxy.md) | no | no | no | alpha | Authentication proxies such as Apache2 mod_auth, etc. |
| [Bitbucket Cloud](Documentation/connectors/bitbucketcloud.md) | yes | yes | no | alpha | |
| [OpenShift](Documentation/connectors/openshift.md) | no | yes | no | stable | |
Stable, beta, and alpha are defined as:
+1 -1
View File
@@ -11,6 +11,7 @@ import (
"github.com/dexidp/dex/connector/mock"
"github.com/dexidp/dex/connector/oidc"
"github.com/dexidp/dex/server"
"github.com/dexidp/dex/storage"
"github.com/dexidp/dex/storage/sql"
)
@@ -215,7 +216,6 @@ logger:
if diff := pretty.Compare(c, want); diff != "" {
t.Errorf("got!=want: %s", diff)
}
}
func TestUnmarshalConfigWithEnv(t *testing.T) {
-1
View File
@@ -182,7 +182,6 @@ func serve(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to initialize storage connectors: %v", err)
}
storageConnectors[i] = conn
}
if c.EnablePasswordDB {
+2 -2
View File
@@ -143,7 +143,7 @@ func cmd() *cobra.Command {
ctx := oidc.ClientContext(context.Background(), a.client)
provider, err := oidc.NewProvider(ctx, issuerURL)
if err != nil {
return fmt.Errorf("Failed to query provider %q: %v", issuerURL, err)
return fmt.Errorf("failed to query provider %q: %v", issuerURL, err)
}
var s struct {
@@ -153,7 +153,7 @@ func cmd() *cobra.Command {
ScopesSupported []string `json:"scopes_supported"`
}
if err := provider.Claims(&s); err != nil {
return fmt.Errorf("Failed to parse provider scopes_supported: %v", err)
return fmt.Errorf("failed to parse provider scopes_supported: %v", err)
}
if len(s.ScopesSupported) == 0 {
@@ -41,7 +41,6 @@ type Config struct {
// Open returns a strategy for logging in through Bitbucket.
func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) {
b := bitbucketConnector{
redirectURI: c.RedirectURI,
teams: c.Teams,
@@ -373,7 +372,6 @@ type userTeamsResponse struct {
}
func (b *bitbucketConnector) userTeams(ctx context.Context, client *http.Client) ([]string, error) {
var teams []string
apiURL := b.apiURL + "/teams?role=member"
@@ -14,7 +14,6 @@ import (
)
func TestUserGroups(t *testing.T) {
teamsResponse := userTeamsResponse{
pagedResponse: pagedResponse{
Size: 3,
@@ -46,7 +45,6 @@ func TestUserGroups(t *testing.T) {
}
func TestUserWithoutTeams(t *testing.T) {
s := newTestServer(map[string]interface{}{
"/teams?role=member": userTeamsResponse{},
})
@@ -61,7 +59,6 @@ func TestUserWithoutTeams(t *testing.T) {
}
func TestUsernameIncludedInFederatedIdentity(t *testing.T) {
s := newTestServer(map[string]interface{}{
"/user": user{Username: "some-login"},
"/user/emails": userEmailResponse{
+2 -4
View File
@@ -67,7 +67,6 @@ type Org struct {
// Open returns a strategy for logging in through GitHub.
func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error) {
if c.Org != "" {
// Return error if both 'org' and 'orgs' fields are used.
if len(c.Orgs) > 0 {
@@ -107,7 +106,6 @@ func (c *Config) Open(id string, logger log.Logger) (connector.Connector, error)
if g.httpClient, err = newHTTPClient(g.rootCA); err != nil {
return nil, fmt.Errorf("failed to create HTTP client: %v", err)
}
}
g.loadAllGroups = c.LoadAllGroups
@@ -144,7 +142,7 @@ type githubConnector struct {
hostName string
// Used to support untrusted/self-signed CA certs.
rootCA string
// HTTP Client that trusts the custom delcared rootCA cert.
// HTTP Client that trusts the custom declared rootCA cert.
httpClient *http.Client
// optional choice between 'name' (default) or 'slug'
teamNameField string
@@ -206,7 +204,7 @@ func (e *oauth2Error) Error() string {
return e.error + ": " + e.errorDescription
}
// newHTTPClient returns a new HTTP client that trusts the custom delcared rootCA cert.
// newHTTPClient returns a new HTTP client that trusts the custom declared rootCA cert.
func newHTTPClient(rootCA string) (*http.Client, error) {
tlsConfig := tls.Config{RootCAs: x509.NewCertPool()}
rootCABytes, err := ioutil.ReadFile(rootCA)
-2
View File
@@ -126,7 +126,6 @@ func TestUserGroupsWithTeamNameAndSlugFieldConfig(t *testing.T) {
// tests that the users login is used as their username when they have no username set
func TestUsernameIncludedInFederatedIdentity(t *testing.T) {
s := newTestServer(map[string]testResponse{
"/user": {data: user{Login: "some-login", ID: 12345678}},
"/user/emails": {data: []userEmail{{
@@ -168,7 +167,6 @@ func TestUsernameIncludedInFederatedIdentity(t *testing.T) {
}
func TestLoginUsedAsIDWhenConfigured(t *testing.T) {
s := newTestServer(map[string]testResponse{
"/user": {data: user{Login: "some-login", ID: 12345678, Name: "Joe Bloggs"}},
"/user/emails": {data: []userEmail{{
-4
View File
@@ -65,7 +65,6 @@ func TestUserGroupsWithoutOrgs(t *testing.T) {
// tests that the email is used as their username when they have no username set
func TestUsernameIncludedInFederatedIdentity(t *testing.T) {
s := newTestServer(map[string]interface{}{
"/api/v4/user": gitlabUser{Email: "some@email.com", ID: 12345678},
"/oauth/token": map[string]interface{}{
@@ -102,7 +101,6 @@ func TestUsernameIncludedInFederatedIdentity(t *testing.T) {
}
func TestLoginUsedAsIDWhenConfigured(t *testing.T) {
s := newTestServer(map[string]interface{}{
"/api/v4/user": gitlabUser{Email: "some@email.com", ID: 12345678, Name: "Joe Bloggs", Username: "joebloggs"},
"/oauth/token": map[string]interface{}{
@@ -130,7 +128,6 @@ func TestLoginUsedAsIDWhenConfigured(t *testing.T) {
}
func TestLoginWithTeamWhitelisted(t *testing.T) {
s := newTestServer(map[string]interface{}{
"/api/v4/user": gitlabUser{Email: "some@email.com", ID: 12345678, Name: "Joe Bloggs"},
"/oauth/token": map[string]interface{}{
@@ -158,7 +155,6 @@ func TestLoginWithTeamWhitelisted(t *testing.T) {
}
func TestLoginWithTeamNonWhitelisted(t *testing.T) {
s := newTestServer(map[string]interface{}{
"/api/v4/user": gitlabUser{Email: "some@email.com", ID: 12345678, Name: "Joe Bloggs", Username: "joebloggs"},
"/oauth/token": map[string]interface{}{
+2 -3
View File
@@ -11,12 +11,12 @@ import (
"github.com/coreos/go-oidc"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
admin "google.golang.org/api/admin/directory/v1"
"github.com/dexidp/dex/connector"
pkg_groups "github.com/dexidp/dex/pkg/groups"
"github.com/dexidp/dex/pkg/log"
"golang.org/x/oauth2/google"
admin "google.golang.org/api/admin/directory/v1"
)
const (
@@ -105,7 +105,6 @@ type googleConnector struct {
redirectURI string
oauth2Config *oauth2.Config
verifier *oidc.IDTokenVerifier
ctx context.Context
cancel context.CancelFunc
logger log.Logger
hostedDomains []string
+3 -1
View File
@@ -150,7 +150,6 @@ func (p *conn) Prompt() string { return "username" }
func (p *conn) Refresh(
ctx context.Context, scopes connector.Scopes, identity connector.Identity) (connector.Identity, error) {
token, err := p.getAdminToken(ctx)
if err != nil {
return identity, fmt.Errorf("keystone: failed to obtain admin token: %v", err)
@@ -210,6 +209,8 @@ func (p *conn) getAdminToken(ctx context.Context) (string, error) {
if err != nil {
return "", err
}
defer resp.Body.Close()
token := resp.Header.Get("X-Subject-Token")
return token, nil
}
@@ -229,6 +230,7 @@ func (p *conn) checkIfUserExists(ctx context.Context, userID string, token strin
if err != nil {
return false, err
}
defer resp.Body.Close()
if resp.StatusCode == 200 {
return true, nil
+14 -3
View File
@@ -154,7 +154,12 @@ func delete(t *testing.T, token, id, uri string) {
t.Fatalf("error: %v", err)
}
req.Header.Set("X-Auth-Token", token)
client.Do(req)
resp, err := client.Do(req)
if err != nil {
t.Fatalf("error: %v", err)
}
defer resp.Body.Close()
}
func createGroup(t *testing.T, token, description, name string) string {
@@ -208,7 +213,13 @@ func addUserToGroup(t *testing.T, token, groupID, userID string) error {
return err
}
req.Header.Set("X-Auth-Token", token)
client.Do(req)
resp, err := client.Do(req)
if err != nil {
t.Fatalf("error: %v", err)
}
defer resp.Body.Close()
return nil
}
@@ -274,7 +285,7 @@ func TestUseRefreshToken(t *testing.T) {
delete(t, token, groupID, groupsURL)
expectEquals(t, 1, len(identityRefresh.Groups))
expectEquals(t, testGroup, string(identityRefresh.Groups[0]))
expectEquals(t, testGroup, identityRefresh.Groups[0])
}
func TestUseRefreshTokenUserDeleted(t *testing.T) {
-2
View File
@@ -189,7 +189,6 @@ func (c *Config) OpenConnector(logger log.Logger) (interface {
}
func (c *Config) openConnector(logger log.Logger) (*ldapConnector, error) {
requiredFields := []struct {
name string
val string
@@ -365,7 +364,6 @@ func (c *ldapConnector) identityFromEntry(user ldap.Entry) (ident connector.Iden
}
func (c *ldapConnector) userEntry(conn *ldap.Conn, username string) (user ldap.Entry, found bool, err error) {
filter := fmt.Sprintf("(%s=%s)", c.UserSearch.Username, ldap.EscapeFilter(username))
if c.UserSearch.Filter != "" {
filter = fmt.Sprintf("(&%s%s)", c.UserSearch.Filter, filter)

Some files were not shown because too many files have changed in this diff Show More