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
04cd1851
Commit
04cd1851
authored
Jan 22, 2016
by
Eric Chiang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
server: add dynamic client registration
parent
9796a1e6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
271 additions
and
42 deletions
+271
-42
main.go
cmd/dex-worker/main.go
+10
-8
client_registration.go
server/client_registration.go
+57
-0
client_registration_test.go
server/client_registration_test.go
+161
-0
config.go
server/config.go
+12
-10
http.go
server/http.go
+14
-13
server.go
server/server.go
+17
-11
No files found.
cmd/dex-worker/main.go
View file @
04cd1851
...
@@ -45,6 +45,7 @@ func main() {
...
@@ -45,6 +45,7 @@ func main() {
emailConfig
:=
fs
.
String
(
"email-cfg"
,
"./static/fixtures/emailer.json"
,
"configures emailer."
)
emailConfig
:=
fs
.
String
(
"email-cfg"
,
"./static/fixtures/emailer.json"
,
"configures emailer."
)
enableRegistration
:=
fs
.
Bool
(
"enable-registration"
,
false
,
"Allows users to self-register"
)
enableRegistration
:=
fs
.
Bool
(
"enable-registration"
,
false
,
"Allows users to self-register"
)
enableClientRegistration
:=
fs
.
Bool
(
"enable-client-registration"
,
false
,
"Allow dynamic registration of clients"
)
noDB
:=
fs
.
Bool
(
"no-db"
,
false
,
"manage entities in-process w/o any encryption, used only for single-node testing"
)
noDB
:=
fs
.
Bool
(
"no-db"
,
false
,
"manage entities in-process w/o any encryption, used only for single-node testing"
)
...
@@ -117,14 +118,15 @@ func main() {
...
@@ -117,14 +118,15 @@ func main() {
}
}
scfg
:=
server
.
ServerConfig
{
scfg
:=
server
.
ServerConfig
{
IssuerURL
:
*
issuer
,
IssuerURL
:
*
issuer
,
TemplateDir
:
*
templates
,
TemplateDir
:
*
templates
,
EmailTemplateDirs
:
emailTemplateDirs
,
EmailTemplateDirs
:
emailTemplateDirs
,
EmailFromAddress
:
*
emailFrom
,
EmailFromAddress
:
*
emailFrom
,
EmailerConfigFile
:
*
emailConfig
,
EmailerConfigFile
:
*
emailConfig
,
IssuerName
:
*
issuerName
,
IssuerName
:
*
issuerName
,
IssuerLogoURL
:
*
issuerLogoURL
,
IssuerLogoURL
:
*
issuerLogoURL
,
EnableRegistration
:
*
enableRegistration
,
EnableRegistration
:
*
enableRegistration
,
EnableClientRegistration
:
*
enableClientRegistration
,
}
}
if
*
noDB
{
if
*
noDB
{
...
...
server/client_registration.go
0 → 100644
View file @
04cd1851
package
server
import
(
"encoding/json"
"net/http"
"github.com/coreos/dex/pkg/log"
"github.com/coreos/go-oidc/oauth2"
"github.com/coreos/go-oidc/oidc"
)
const
(
invalidRedirectURI
=
"invalid_redirect_uri"
invalidClientMetadata
=
"invalid_client_metadata"
)
func
(
s
*
Server
)
handleClientRegistration
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
resp
,
err
:=
s
.
handleClientRegistrationRequest
(
r
)
if
err
!=
nil
{
code
:=
http
.
StatusBadRequest
if
err
.
Type
==
oauth2
.
ErrorServerError
{
code
=
http
.
StatusInternalServerError
}
writeResponseWithBody
(
w
,
code
,
err
)
}
else
{
writeResponseWithBody
(
w
,
http
.
StatusCreated
,
resp
)
}
}
func
(
s
*
Server
)
handleClientRegistrationRequest
(
r
*
http
.
Request
)
(
*
oidc
.
ClientRegistrationResponse
,
*
apiError
)
{
var
clientMetadata
oidc
.
ClientMetadata
if
err
:=
json
.
NewDecoder
(
r
.
Body
)
.
Decode
(
&
clientMetadata
);
err
!=
nil
{
return
nil
,
newAPIError
(
oauth2
.
ErrorInvalidRequest
,
err
.
Error
())
}
if
err
:=
s
.
ProviderConfig
()
.
Supports
(
clientMetadata
);
err
!=
nil
{
return
nil
,
newAPIError
(
invalidClientMetadata
,
err
.
Error
())
}
// metadata is guarenteed to have at least one redirect_uri by earlier validation.
id
,
err
:=
oidc
.
GenClientID
(
clientMetadata
.
RedirectURIs
[
0
]
.
Host
)
if
err
!=
nil
{
log
.
Errorf
(
"Faild to create client ID: %v"
,
err
)
return
nil
,
newAPIError
(
oauth2
.
ErrorServerError
,
"unable to save client metadata"
)
}
creds
,
err
:=
s
.
ClientIdentityRepo
.
New
(
id
,
clientMetadata
)
if
err
!=
nil
{
log
.
Errorf
(
"Failed to create new client identity: %v"
,
err
)
return
nil
,
newAPIError
(
oauth2
.
ErrorServerError
,
"unable to save client metadata"
)
}
return
&
oidc
.
ClientRegistrationResponse
{
ClientID
:
creds
.
ID
,
ClientSecret
:
creds
.
Secret
,
ClientMetadata
:
clientMetadata
,
},
nil
}
server/client_registration_test.go
0 → 100644
View file @
04cd1851
package
server
import
(
"encoding/json"
"errors"
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
"github.com/coreos/go-oidc/oauth2"
"github.com/coreos/go-oidc/oidc"
"github.com/kylelemons/godebug/pretty"
)
func
TestClientRegistration
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
body
string
code
int
}{
{
""
,
http
.
StatusBadRequest
},
{
`{
"redirect_uris": [
"https://client.example.org/callback",
"https://client.example.org/callback2"
]
}`
,
http
.
StatusCreated
,
},
{
// Requesting unsupported client metadata fields (user_info_encrypted).
`{
"application_type": "web",
"redirect_uris":[
"https://client.example.org/callback",
"https://client.example.org/callback2"
],
"client_name": "My Example",
"logo_uri": "https://client.example.org/logo.png",
"subject_type": "pairwise",
"sector_identifier_uri": "https://other.example.net/file_of_redirect_uris.json",
"token_endpoint_auth_method": "client_secret_basic",
"jwks_uri": "https://client.example.org/my_public_keys.jwks",
"userinfo_encrypted_response_alg": "RSA1_5",
"userinfo_encrypted_response_enc": "A128CBC-HS256",
"contacts": ["ve7jtb@example.org", "mary@example.org"],
"request_uris": [
"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA" ]
}`
,
http
.
StatusBadRequest
,
},
{
`{
"application_type": "web",
"redirect_uris":[
"https://client.example.org/callback",
"https://client.example.org/callback2"
],
"client_name": "My Example",
"logo_uri": "https://client.example.org/logo.png",
"subject_type": "pairwise",
"sector_identifier_uri": "https://other.example.net/file_of_redirect_uris.json",
"token_endpoint_auth_method": "client_secret_basic",
"jwks_uri": "https://client.example.org/my_public_keys.jwks",
"contacts": ["ve7jtb@example.org", "mary@example.org"],
"request_uris": [
"https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA" ]
}`
,
http
.
StatusCreated
,
},
}
var
handler
http
.
Handler
f
:=
http
.
HandlerFunc
(
func
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
handler
.
ServeHTTP
(
w
,
r
)
})
testServer
:=
httptest
.
NewServer
(
f
)
issuerURL
,
err
:=
url
.
Parse
(
testServer
.
URL
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
defer
testServer
.
Close
()
for
i
,
tt
:=
range
tests
{
fixtures
,
err
:=
makeTestFixtures
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
fixtures
.
srv
.
IssuerURL
=
*
issuerURL
fixtures
.
srv
.
EnableClientRegistration
=
true
handler
=
fixtures
.
srv
.
HTTPHandler
()
err
=
func
()
error
{
// GET provider config through discovery URL.
resp
,
err
:=
http
.
Get
(
testServer
.
URL
+
"/.well-known/openid-configuration"
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"GET config: %v"
,
err
)
}
var
cfg
oidc
.
ProviderConfig
err
=
json
.
NewDecoder
(
resp
.
Body
)
.
Decode
(
&
cfg
)
resp
.
Body
.
Close
()
if
err
!=
nil
{
return
fmt
.
Errorf
(
"decode resp: %v"
,
err
)
}
if
cfg
.
RegistrationEndpoint
==
nil
{
return
errors
.
New
(
"registration endpoint not available"
)
}
// POST registration request to registration endpoint.
body
:=
strings
.
NewReader
(
tt
.
body
)
resp
,
err
=
http
.
Post
(
cfg
.
RegistrationEndpoint
.
String
(),
"application/json"
,
body
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"POSTing client metadata: %v"
,
err
)
}
defer
resp
.
Body
.
Close
()
if
resp
.
StatusCode
!=
tt
.
code
{
return
fmt
.
Errorf
(
"expected status code=%d, got=%d"
,
tt
.
code
,
resp
.
StatusCode
)
}
if
resp
.
StatusCode
!=
http
.
StatusCreated
{
var
oauthErr
oauth2
.
Error
if
err
:=
json
.
NewDecoder
(
resp
.
Body
)
.
Decode
(
&
oauthErr
);
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to decode oauth2 error: %v"
,
err
)
}
if
oauthErr
.
Type
==
""
{
return
fmt
.
Errorf
(
"got oauth2 error with no 'error' field"
)
}
return
nil
}
// Read registration response.
var
r
oidc
.
ClientRegistrationResponse
if
err
:=
json
.
NewDecoder
(
resp
.
Body
)
.
Decode
(
&
r
);
err
!=
nil
{
return
fmt
.
Errorf
(
"decode response: %v"
,
err
)
}
if
r
.
ClientID
==
""
{
return
fmt
.
Errorf
(
"no client id in registration response"
)
}
metadata
,
err
:=
fixtures
.
clientIdentityRepo
.
Metadata
(
r
.
ClientID
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"failed to lookup client id after creation"
)
}
if
diff
:=
pretty
.
Compare
(
&
metadata
,
&
r
.
ClientMetadata
);
diff
!=
""
{
return
fmt
.
Errorf
(
"metadata in response did not match metadata in db: %s"
,
diff
)
}
return
nil
}()
if
err
!=
nil
{
t
.
Errorf
(
"case %d: %v"
,
i
,
err
)
}
}
}
server/config.go
View file @
04cd1851
...
@@ -26,15 +26,16 @@ import (
...
@@ -26,15 +26,16 @@ import (
)
)
type
ServerConfig
struct
{
type
ServerConfig
struct
{
IssuerURL
string
IssuerURL
string
IssuerName
string
IssuerName
string
IssuerLogoURL
string
IssuerLogoURL
string
TemplateDir
string
TemplateDir
string
EmailTemplateDirs
[]
string
EmailTemplateDirs
[]
string
EmailFromAddress
string
EmailFromAddress
string
EmailerConfigFile
string
EmailerConfigFile
string
StateConfig
StateConfigurer
StateConfig
StateConfigurer
EnableRegistration
bool
EnableRegistration
bool
EnableClientRegistration
bool
}
}
type
StateConfigurer
interface
{
type
StateConfigurer
interface
{
...
@@ -73,7 +74,8 @@ func (cfg *ServerConfig) Server() (*Server, error) {
...
@@ -73,7 +74,8 @@ func (cfg *ServerConfig) Server() (*Server, error) {
HealthChecks
:
[]
health
.
Checkable
{
km
},
HealthChecks
:
[]
health
.
Checkable
{
km
},
Connectors
:
[]
connector
.
Connector
{},
Connectors
:
[]
connector
.
Connector
{},
EnableRegistration
:
cfg
.
EnableRegistration
,
EnableRegistration
:
cfg
.
EnableRegistration
,
EnableClientRegistration
:
cfg
.
EnableClientRegistration
,
}
}
err
=
cfg
.
StateConfig
.
Configure
(
&
srv
)
err
=
cfg
.
StateConfig
.
Configure
(
&
srv
)
...
...
server/http.go
View file @
04cd1851
...
@@ -29,19 +29,20 @@ const (
...
@@ -29,19 +29,20 @@ const (
)
)
var
(
var
(
httpPathDiscovery
=
"/.well-known/openid-configuration"
httpPathDiscovery
=
"/.well-known/openid-configuration"
httpPathToken
=
"/token"
httpPathToken
=
"/token"
httpPathKeys
=
"/keys"
httpPathKeys
=
"/keys"
httpPathAuth
=
"/auth"
httpPathAuth
=
"/auth"
httpPathHealth
=
"/health"
httpPathHealth
=
"/health"
httpPathAPI
=
"/api"
httpPathAPI
=
"/api"
httpPathRegister
=
"/register"
httpPathRegister
=
"/register"
httpPathEmailVerify
=
"/verify-email"
httpPathEmailVerify
=
"/verify-email"
httpPathVerifyEmailResend
=
"/resend-verify-email"
httpPathVerifyEmailResend
=
"/resend-verify-email"
httpPathSendResetPassword
=
"/send-reset-password"
httpPathSendResetPassword
=
"/send-reset-password"
httpPathResetPassword
=
"/reset-password"
httpPathResetPassword
=
"/reset-password"
httpPathAcceptInvitation
=
"/accept-invitation"
httpPathAcceptInvitation
=
"/accept-invitation"
httpPathDebugVars
=
"/debug/vars"
httpPathDebugVars
=
"/debug/vars"
httpPathClientRegistration
=
"/registration"
cookieLastSeen
=
"LastSeen"
cookieLastSeen
=
"LastSeen"
cookieShowEmailVerifiedMessage
=
"ShowEmailVerifiedMessage"
cookieShowEmailVerifiedMessage
=
"ShowEmailVerifiedMessage"
...
...
server/server.go
View file @
04cd1851
...
@@ -74,6 +74,7 @@ type Server struct {
...
@@ -74,6 +74,7 @@ type Server struct {
RefreshTokenRepo
refresh
.
RefreshTokenRepo
RefreshTokenRepo
refresh
.
RefreshTokenRepo
UserEmailer
*
useremail
.
UserEmailer
UserEmailer
*
useremail
.
UserEmailer
EnableRegistration
bool
EnableRegistration
bool
EnableClientRegistration
bool
localConnectorID
string
localConnectorID
string
}
}
...
@@ -110,19 +111,15 @@ func (s *Server) KillSession(sessionKey string) error {
...
@@ -110,19 +111,15 @@ func (s *Server) KillSession(sessionKey string) error {
return
err
return
err
}
}
func
(
s
*
Server
)
pathURL
(
path
string
)
*
url
.
URL
{
u
:=
s
.
IssuerURL
u
.
Path
=
path
return
&
u
}
func
(
s
*
Server
)
ProviderConfig
()
oidc
.
ProviderConfig
{
func
(
s
*
Server
)
ProviderConfig
()
oidc
.
ProviderConfig
{
authEndpoint
:=
s
.
absURL
(
httpPathAuth
)
tokenEndpoint
:=
s
.
absURL
(
httpPathToken
)
keysEndpoint
:=
s
.
absURL
(
httpPathKeys
)
cfg
:=
oidc
.
ProviderConfig
{
cfg
:=
oidc
.
ProviderConfig
{
Issuer
:
&
s
.
IssuerURL
,
Issuer
:
&
s
.
IssuerURL
,
AuthEndpoint
:
&
authEndpoint
,
AuthEndpoint
:
s
.
pathURL
(
httpPathAuth
),
TokenEndpoint
:
&
tokenEndpoint
,
TokenEndpoint
:
s
.
pathURL
(
httpPathToken
),
KeysEndpoint
:
&
keysEndpoint
,
KeysEndpoint
:
s
.
pathURL
(
httpPathKeys
),
GrantTypesSupported
:
[]
string
{
oauth2
.
GrantTypeAuthCode
,
oauth2
.
GrantTypeClientCreds
},
GrantTypesSupported
:
[]
string
{
oauth2
.
GrantTypeAuthCode
,
oauth2
.
GrantTypeClientCreds
},
ResponseTypesSupported
:
[]
string
{
"code"
},
ResponseTypesSupported
:
[]
string
{
"code"
},
...
@@ -131,6 +128,11 @@ func (s *Server) ProviderConfig() oidc.ProviderConfig {
...
@@ -131,6 +128,11 @@ func (s *Server) ProviderConfig() oidc.ProviderConfig {
TokenEndpointAuthMethodsSupported
:
[]
string
{
"client_secret_basic"
},
TokenEndpointAuthMethodsSupported
:
[]
string
{
"client_secret_basic"
},
}
}
if
s
.
EnableClientRegistration
{
regEndpoint
:=
s
.
absURL
(
httpPathClientRegistration
)
cfg
.
RegistrationEndpoint
=
&
regEndpoint
}
return
cfg
return
cfg
}
}
...
@@ -246,6 +248,10 @@ func (s *Server) HTTPHandler() http.Handler {
...
@@ -246,6 +248,10 @@ func (s *Server) HTTPHandler() http.Handler {
redirectValidityWindow
:
s
.
SessionManager
.
ValidityWindow
,
redirectValidityWindow
:
s
.
SessionManager
.
ValidityWindow
,
})
})
if
s
.
EnableClientRegistration
{
mux
.
HandleFunc
(
httpPathClientRegistration
,
s
.
handleClientRegistration
)
}
mux
.
HandleFunc
(
httpPathDebugVars
,
health
.
ExpvarHandler
)
mux
.
HandleFunc
(
httpPathDebugVars
,
health
.
ExpvarHandler
)
pcfg
:=
s
.
ProviderConfig
()
pcfg
:=
s
.
ProviderConfig
()
...
...
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