Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
D
dex
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
dex
Commits
d4274eb0
Commit
d4274eb0
authored
Apr 11, 2017
by
rithu leena john
Committed by
GitHub
Apr 11, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #901 from rithujohn191/github-api
connector/github: add support for github enterprise.
parents
43ad9cc3
76b9eb1d
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
125 additions
and
6 deletions
+125
-6
github-connector.md
Documentation/github-connector.md
+33
-0
github.go
connector/github/github.go
+92
-6
No files found.
Documentation/github-connector.md
View file @
d4274eb0
...
...
@@ -31,4 +31,37 @@ connectors:
org
:
my-oranization
```
## GitHub Enterprise
Users can use their GitHub Enterprise account to login to dex. The following configuration can be used to enable a GitHub Enterprise connector on dex:
```
yaml
connectors
:
-
type
:
github
# Required field for connector id.
id
:
github
# Required field for connector name.
name
:
GitHub
config
:
# Required fields. Dex must be pre-registered with GitHub Enterprise
# to get the following values.
# Credentials can be string literals or pulled from the environment.
clientID
:
$GITHUB_CLIENT_ID
clientSecret
:
$GITHUB_CLIENT_SECRET
redirectURI
:
http://127.0.0.1:5556/dex/callback
# Optional organization to pull teams from, communicate through the
# "groups" scope.
#
# NOTE: This is an EXPERIMENTAL config option and will likely change.
org
:
my-oranization
# Required ONLY for GitHub Enterprise.
# This is the Hostname of the GitHub Enterprise account listed on the
# management console. Ensure this domain is routable on your network.
hostName
:
git.example.com
# ONLY for GitHub Enterprise. Optional field.
# Used to support self-signed or untrusted CA root certificates.
rootCA
:
/etc/dex/ca.crt
```
[
github-oauth2
]:
https://github.com/settings/applications/new
connector/github/github.go
View file @
d4274eb0
...
...
@@ -3,13 +3,18 @@ package github
import
(
"context"
"crypto/tls"
"crypto/x509"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net"
"net/http"
"regexp"
"strconv"
"strings"
"time"
"golang.org/x/oauth2"
"golang.org/x/oauth2/github"
...
...
@@ -19,7 +24,7 @@ import (
)
const
(
baseURL
=
"https://api.github.com"
apiURL
=
"https://api.github.com"
scopeEmail
=
"user:email"
scopeOrgs
=
"read:org"
)
...
...
@@ -30,17 +35,45 @@ type Config struct {
ClientSecret
string
`json:"clientSecret"`
RedirectURI
string
`json:"redirectURI"`
Org
string
`json:"org"`
HostName
string
`json:"hostName"`
RootCA
string
`json:"rootCA"`
}
// Open returns a strategy for logging in through GitHub.
func
(
c
*
Config
)
Open
(
logger
logrus
.
FieldLogger
)
(
connector
.
Connector
,
error
)
{
return
&
githubConnector
{
g
:=
githubConnector
{
redirectURI
:
c
.
RedirectURI
,
org
:
c
.
Org
,
clientID
:
c
.
ClientID
,
clientSecret
:
c
.
ClientSecret
,
apiURL
:
apiURL
,
logger
:
logger
,
},
nil
}
if
c
.
HostName
!=
""
{
// ensure this is a hostname and not a URL or path.
if
strings
.
Contains
(
c
.
HostName
,
"/"
)
{
return
nil
,
errors
.
New
(
"invalid hostname: hostname cannot contain `/`"
)
}
g
.
hostName
=
c
.
HostName
g
.
apiURL
=
"https://"
+
c
.
HostName
+
"/api/v3"
}
if
c
.
RootCA
!=
""
{
if
c
.
HostName
==
""
{
return
nil
,
errors
.
New
(
"invalid connector config: Host name field required for a root certificate file"
)
}
g
.
rootCA
=
c
.
RootCA
var
err
error
if
g
.
httpClient
,
err
=
newHTTPClient
(
g
.
rootCA
);
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"failed to create HTTP client: %v"
,
err
)
}
}
return
&
g
,
nil
}
type
connectorData
struct
{
...
...
@@ -59,6 +92,14 @@ type githubConnector struct {
clientID
string
clientSecret
string
logger
logrus
.
FieldLogger
// apiURL defaults to "https://api.github.com"
apiURL
string
// hostName of the GitHub enterprise account.
hostName
string
// Used to support untrusted/self-signed CA certs.
rootCA
string
// HTTP Client that trusts the custom delcared rootCA cert.
httpClient
*
http
.
Client
}
func
(
c
*
githubConnector
)
oauth2Config
(
scopes
connector
.
Scopes
)
*
oauth2
.
Config
{
...
...
@@ -68,10 +109,21 @@ func (c *githubConnector) oauth2Config(scopes connector.Scopes) *oauth2.Config {
}
else
{
githubScopes
=
[]
string
{
scopeEmail
}
}
endpoint
:=
github
.
Endpoint
// case when it is a GitHub Enterprise account.
if
c
.
hostName
!=
""
{
endpoint
=
oauth2
.
Endpoint
{
AuthURL
:
"https://"
+
c
.
hostName
+
"/login/oauth/authorize"
,
TokenURL
:
"https://"
+
c
.
hostName
+
"/login/oauth/access_token"
,
}
}
return
&
oauth2
.
Config
{
ClientID
:
c
.
clientID
,
ClientSecret
:
c
.
clientSecret
,
Endpoint
:
github
.
E
ndpoint
,
Endpoint
:
e
ndpoint
,
Scopes
:
githubScopes
,
}
}
...
...
@@ -80,6 +132,7 @@ func (c *githubConnector) LoginURL(scopes connector.Scopes, callbackURL, state s
if
c
.
redirectURI
!=
callbackURL
{
return
""
,
fmt
.
Errorf
(
"expected callback URL did not match the URL in the config"
)
}
return
c
.
oauth2Config
(
scopes
)
.
AuthCodeURL
(
state
),
nil
}
...
...
@@ -95,6 +148,34 @@ func (e *oauth2Error) Error() string {
return
e
.
error
+
": "
+
e
.
errorDescription
}
// newHTTPClient returns a new HTTP client that trusts the custom delcared rootCA cert.
func
newHTTPClient
(
rootCA
string
)
(
*
http
.
Client
,
error
)
{
tlsConfig
:=
tls
.
Config
{
RootCAs
:
x509
.
NewCertPool
()}
rootCABytes
,
err
:=
ioutil
.
ReadFile
(
rootCA
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"failed to read root-ca: %v"
,
err
)
}
if
!
tlsConfig
.
RootCAs
.
AppendCertsFromPEM
(
rootCABytes
)
{
return
nil
,
fmt
.
Errorf
(
"no certs found in root CA file %q"
,
rootCA
)
}
return
&
http
.
Client
{
Transport
:
&
http
.
Transport
{
TLSClientConfig
:
&
tlsConfig
,
Proxy
:
http
.
ProxyFromEnvironment
,
DialContext
:
(
&
net
.
Dialer
{
Timeout
:
30
*
time
.
Second
,
KeepAlive
:
30
*
time
.
Second
,
DualStack
:
true
,
})
.
DialContext
,
MaxIdleConns
:
100
,
IdleConnTimeout
:
90
*
time
.
Second
,
TLSHandshakeTimeout
:
10
*
time
.
Second
,
ExpectContinueTimeout
:
1
*
time
.
Second
,
},
},
nil
}
func
(
c
*
githubConnector
)
HandleCallback
(
s
connector
.
Scopes
,
r
*
http
.
Request
)
(
identity
connector
.
Identity
,
err
error
)
{
q
:=
r
.
URL
.
Query
()
if
errType
:=
q
.
Get
(
"error"
);
errType
!=
""
{
...
...
@@ -102,7 +183,12 @@ func (c *githubConnector) HandleCallback(s connector.Scopes, r *http.Request) (i
}
oauth2Config
:=
c
.
oauth2Config
(
s
)
ctx
:=
r
.
Context
()
// GitHub Enterprise account
if
c
.
httpClient
!=
nil
{
ctx
=
context
.
WithValue
(
r
.
Context
(),
oauth2
.
HTTPClient
,
c
.
httpClient
)
}
token
,
err
:=
oauth2Config
.
Exchange
(
ctx
,
q
.
Get
(
"code"
))
if
err
!=
nil
{
...
...
@@ -192,7 +278,7 @@ type user struct {
// a bearer token as part of the request.
func
(
c
*
githubConnector
)
user
(
ctx
context
.
Context
,
client
*
http
.
Client
)
(
user
,
error
)
{
var
u
user
req
,
err
:=
http
.
NewRequest
(
"GET"
,
base
URL
+
"/user"
,
nil
)
req
,
err
:=
http
.
NewRequest
(
"GET"
,
c
.
api
URL
+
"/user"
,
nil
)
if
err
!=
nil
{
return
u
,
fmt
.
Errorf
(
"github: new req: %v"
,
err
)
}
...
...
@@ -228,7 +314,7 @@ func (c *githubConnector) teams(ctx context.Context, client *http.Client, org st
// https://developer.github.com/v3/#pagination
reNext
:=
regexp
.
MustCompile
(
"<(.*)>; rel=
\"
next
\"
"
)
reLast
:=
regexp
.
MustCompile
(
"<(.*)>; rel=
\"
last
\"
"
)
apiURL
:=
base
URL
+
"/user/teams"
apiURL
:=
c
.
api
URL
+
"/user/teams"
for
{
req
,
err
:=
http
.
NewRequest
(
"GET"
,
apiURL
,
nil
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment