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
691476b4
Commit
691476b4
authored
Oct 13, 2016
by
Eric Chiang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
storage/kubernetes: manage third party resources and drop support for 1.3
parent
f3783649
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
146 additions
and
38 deletions
+146
-38
client.go
storage/kubernetes/client.go
+31
-29
storage.go
storage/kubernetes/storage.go
+51
-3
storage_test.go
storage/kubernetes/storage_test.go
+1
-1
types.go
storage/kubernetes/types.go
+63
-5
No files found.
storage/kubernetes/client.go
View file @
691476b4
...
...
@@ -20,6 +20,7 @@ import (
"time"
"github.com/gtank/cryptopasta"
"golang.org/x/net/context"
yaml
"gopkg.in/yaml.v2"
"github.com/coreos/dex/storage"
...
...
@@ -27,27 +28,17 @@ import (
)
type
client
struct
{
client
*
http
.
Client
baseURL
string
namespace
string
apiVersion
string
client
*
http
.
Client
baseURL
string
namespace
string
now
func
()
time
.
Time
// API version of the oidc resources. For example "oidc.coreos.com". This is
// currently not configurable, but could be in the future.
apiVersion
string
// BUG: currently each third party API group can only have one resource in it,
// so for each resource this storage uses, it need a unique API group.
//
// Prepend the name of each resource to the API group for a predictable mapping.
//
// See: https://github.com/kubernetes/kubernetes/pull/28414
prependResourceNameToAPIGroup
bool
}
func
(
c
*
client
)
apiVersionForResource
(
resource
string
)
string
{
if
!
c
.
prependResourceNameToAPIGroup
{
return
c
.
apiVersion
}
return
resource
+
"."
+
c
.
apiVersion
// This is called once the client's Close method is called to signal goroutines,
// such as the one creating third party resources, to stop.
cancel
context
.
CancelFunc
}
func
(
c
*
client
)
urlFor
(
apiVersion
,
namespace
,
resource
,
name
string
)
string
{
...
...
@@ -56,10 +47,6 @@ func (c *client) urlFor(apiVersion, namespace, resource, name string) string {
basePath
=
"api/"
}
if
c
.
prependResourceNameToAPIGroup
&&
apiVersion
!=
""
&&
resource
!=
""
{
apiVersion
=
resource
+
"."
+
apiVersion
}
var
p
string
if
namespace
!=
""
{
p
=
path
.
Join
(
basePath
,
apiVersion
,
"namespaces"
,
namespace
,
resource
,
name
)
...
...
@@ -72,15 +59,28 @@ func (c *client) urlFor(apiVersion, namespace, resource, name string) string {
return
c
.
baseURL
+
"/"
+
p
}
// Define an error interface so we can get at the underlying status code if it's
// absolutely necessary. For instance when we need to see if an error indicates
// a resource already exists.
type
httpError
interface
{
StatusCode
()
int
}
var
_
httpError
=
(
*
httpErr
)(
nil
)
type
httpErr
struct
{
method
string
url
string
status
string
status
int
body
[]
byte
}
func
(
e
*
httpErr
)
StatusCode
()
int
{
return
e
.
status
}
func
(
e
*
httpErr
)
Error
()
string
{
return
fmt
.
Sprintf
(
"%s %s %s: response from server
\"
%s
\"
"
,
e
.
method
,
e
.
url
,
e
.
status
,
bytes
.
TrimSpace
(
e
.
body
))
return
fmt
.
Sprintf
(
"%s %s %s: response from server
\"
%s
\"
"
,
e
.
method
,
e
.
url
,
http
.
StatusText
(
e
.
status
)
,
bytes
.
TrimSpace
(
e
.
body
))
}
func
checkHTTPErr
(
r
*
http
.
Response
,
validStatusCodes
...
int
)
error
{
...
...
@@ -100,7 +100,7 @@ func checkHTTPErr(r *http.Response, validStatusCodes ...int) error {
method
=
r
.
Request
.
Method
url
=
r
.
Request
.
URL
.
String
()
}
err
=
&
httpErr
{
method
,
url
,
r
.
Status
,
body
}
err
=
&
httpErr
{
method
,
url
,
r
.
Status
Code
,
body
}
log
.
Printf
(
"%s"
,
err
)
if
r
.
StatusCode
==
http
.
StatusNotFound
{
...
...
@@ -134,12 +134,16 @@ func (c *client) list(resource string, v interface{}) error {
}
func
(
c
*
client
)
post
(
resource
string
,
v
interface
{})
error
{
return
c
.
postResource
(
c
.
apiVersion
,
c
.
namespace
,
resource
,
v
)
}
func
(
c
*
client
)
postResource
(
apiVersion
,
namespace
,
resource
string
,
v
interface
{})
error
{
body
,
err
:=
json
.
Marshal
(
v
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"marshal object: %v"
,
err
)
}
url
:=
c
.
urlFor
(
c
.
apiVersion
,
c
.
namespace
,
resource
,
""
)
url
:=
c
.
urlFor
(
apiVersion
,
namespace
,
resource
,
""
)
resp
,
err
:=
c
.
client
.
Post
(
url
,
"application/json"
,
bytes
.
NewReader
(
body
))
if
err
!=
nil
{
return
err
...
...
@@ -277,8 +281,6 @@ func newClient(cluster k8sapi.Cluster, user k8sapi.AuthInfo, namespace string) (
baseURL
:
cluster
.
Server
,
namespace
:
namespace
,
apiVersion
:
"oidc.coreos.com/v1"
,
now
:
time
.
Now
,
prependResourceNameToAPIGroup
:
true
,
},
nil
}
...
...
storage/kubernetes/storage.go
View file @
691476b4
...
...
@@ -4,11 +4,13 @@ import (
"errors"
"fmt"
"log"
"net/http"
"os"
"path/filepath"
"time"
homedir
"github.com/mitchellh/go-homedir"
"golang.org/x/net/context"
"github.com/coreos/dex/storage"
"github.com/coreos/dex/storage/kubernetes/k8sapi"
...
...
@@ -45,7 +47,6 @@ func (c *Config) Open() (storage.Storage, error) {
if
err
!=
nil
{
return
nil
,
err
}
return
cli
,
nil
}
...
...
@@ -81,10 +82,57 @@ func (c *Config) open() (*client, error) {
return
nil
,
err
}
return
newClient
(
cluster
,
user
,
namespace
)
cli
,
err
:=
newClient
(
cluster
,
user
,
namespace
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"create client: %v"
,
err
)
}
// Don't try to synchronize this because creating third party resources is not
// a synchronous event. Even after the API server returns a 200, it can still
// take several seconds for them to actually appear.
ctx
,
cancel
:=
context
.
WithCancel
(
context
.
Background
())
go
func
()
{
for
{
if
err
:=
cli
.
createThirdPartyResources
();
err
!=
nil
{
log
.
Printf
(
"failed creating third party resources: %v"
,
err
)
}
else
{
return
}
select
{
case
<-
ctx
.
Done
()
:
return
case
<-
time
.
After
(
30
*
time
.
Second
)
:
}
}
}()
// If the client is closed, stop trying to create third party resources.
cli
.
cancel
=
cancel
return
cli
,
nil
}
func
(
cli
*
client
)
createThirdPartyResources
()
error
{
for
_
,
r
:=
range
thirdPartyResources
{
err
:=
cli
.
postResource
(
"extensions/v1beta1"
,
""
,
"thirdpartyresources"
,
r
)
if
err
!=
nil
{
if
e
,
ok
:=
err
.
(
httpError
);
ok
{
if
e
.
StatusCode
()
==
http
.
StatusConflict
{
log
.
Printf
(
"third party resource already created %q"
,
r
.
ObjectMeta
.
Name
)
continue
}
}
return
err
}
log
.
Printf
(
"create third party resource %q"
,
r
.
ObjectMeta
.
Name
)
}
return
nil
}
func
(
cli
*
client
)
Close
()
error
{
if
cli
.
cancel
!=
nil
{
cli
.
cancel
()
}
return
nil
}
...
...
@@ -108,7 +156,7 @@ func (cli *client) CreateRefresh(r storage.RefreshToken) error {
refresh
:=
RefreshToken
{
TypeMeta
:
k8sapi
.
TypeMeta
{
Kind
:
kindRefreshToken
,
APIVersion
:
cli
.
apiVersion
ForResource
(
resourceRefreshToken
)
,
APIVersion
:
cli
.
apiVersion
,
},
ObjectMeta
:
k8sapi
.
ObjectMeta
{
Name
:
r
.
RefreshToken
,
...
...
storage/kubernetes/storage_test.go
View file @
691476b4
...
...
@@ -60,7 +60,7 @@ func TestURLFor(t *testing.T) {
}
for
_
,
test
:=
range
tests
{
c
:=
&
client
{
baseURL
:
test
.
baseURL
,
prependResourceNameToAPIGroup
:
false
}
c
:=
&
client
{
baseURL
:
test
.
baseURL
}
got
:=
c
.
urlFor
(
test
.
apiVersion
,
test
.
namespace
,
test
.
resource
,
test
.
name
)
if
got
!=
test
.
want
{
t
.
Errorf
(
"(&client{baseURL:%q}).urlFor(%q, %q, %q, %q): expected %q got %q"
,
...
...
storage/kubernetes/types.go
View file @
691476b4
...
...
@@ -11,6 +11,64 @@ import (
"github.com/coreos/dex/storage/kubernetes/k8sapi"
)
var
tprMeta
=
k8sapi
.
TypeMeta
{
APIVersion
:
"extensions/v1beta1"
,
Kind
:
"ThirdPartyResource"
,
}
// The set of third party resources required by the storage. These are managed by
// the storage so it can migrate itself by creating new resources.
var
thirdPartyResources
=
[]
k8sapi
.
ThirdPartyResource
{
{
ObjectMeta
:
k8sapi
.
ObjectMeta
{
Name
:
"auth-code.oidc.coreos.com"
,
},
TypeMeta
:
tprMeta
,
Description
:
"A code which can be claimed for an access token."
,
Versions
:
[]
k8sapi
.
APIVersion
{{
Name
:
"v1"
}},
},
{
ObjectMeta
:
k8sapi
.
ObjectMeta
{
Name
:
"auth-request.oidc.coreos.com"
,
},
TypeMeta
:
tprMeta
,
Description
:
"A request for an end user to authorize a client."
,
Versions
:
[]
k8sapi
.
APIVersion
{{
Name
:
"v1"
}},
},
{
ObjectMeta
:
k8sapi
.
ObjectMeta
{
Name
:
"o-auth2-client.oidc.coreos.com"
,
},
TypeMeta
:
tprMeta
,
Description
:
"An OpenID Connect client."
,
Versions
:
[]
k8sapi
.
APIVersion
{{
Name
:
"v1"
}},
},
{
ObjectMeta
:
k8sapi
.
ObjectMeta
{
Name
:
"signing-key.oidc.coreos.com"
,
},
TypeMeta
:
tprMeta
,
Description
:
"Keys used to sign and verify OpenID Connect tokens."
,
Versions
:
[]
k8sapi
.
APIVersion
{{
Name
:
"v1"
}},
},
{
ObjectMeta
:
k8sapi
.
ObjectMeta
{
Name
:
"refresh-token.oidc.coreos.com"
,
},
TypeMeta
:
tprMeta
,
Description
:
"Refresh tokens for clients to continuously act on behalf of an end user."
,
Versions
:
[]
k8sapi
.
APIVersion
{{
Name
:
"v1"
}},
},
{
ObjectMeta
:
k8sapi
.
ObjectMeta
{
Name
:
"password.oidc.coreos.com"
,
},
TypeMeta
:
tprMeta
,
Description
:
"Passwords managed by the OIDC server."
,
Versions
:
[]
k8sapi
.
APIVersion
{{
Name
:
"v1"
}},
},
}
// There will only ever be a single keys resource. Maintain this by setting a
// common name.
const
keysName
=
"openid-connect-keys"
...
...
@@ -45,7 +103,7 @@ func (cli *client) fromStorageClient(c storage.Client) Client {
return
Client
{
TypeMeta
:
k8sapi
.
TypeMeta
{
Kind
:
kindClient
,
APIVersion
:
cli
.
apiVersion
ForResource
(
resourceClient
)
,
APIVersion
:
cli
.
apiVersion
,
},
ObjectMeta
:
k8sapi
.
ObjectMeta
{
Name
:
c
.
ID
,
...
...
@@ -162,7 +220,7 @@ func (cli *client) fromStorageAuthRequest(a storage.AuthRequest) AuthRequest {
req
:=
AuthRequest
{
TypeMeta
:
k8sapi
.
TypeMeta
{
Kind
:
kindAuthRequest
,
APIVersion
:
cli
.
apiVersion
ForResource
(
resourceAuthRequest
)
,
APIVersion
:
cli
.
apiVersion
,
},
ObjectMeta
:
k8sapi
.
ObjectMeta
{
Name
:
a
.
ID
,
...
...
@@ -216,7 +274,7 @@ func (cli *client) fromStoragePassword(p storage.Password) Password {
return
Password
{
TypeMeta
:
k8sapi
.
TypeMeta
{
Kind
:
kindPassword
,
APIVersion
:
cli
.
apiVersion
ForResource
(
resourcePassword
)
,
APIVersion
:
cli
.
apiVersion
,
},
ObjectMeta
:
k8sapi
.
ObjectMeta
{
Name
:
emailToID
(
email
),
...
...
@@ -270,7 +328,7 @@ func (cli *client) fromStorageAuthCode(a storage.AuthCode) AuthCode {
return
AuthCode
{
TypeMeta
:
k8sapi
.
TypeMeta
{
Kind
:
kindAuthCode
,
APIVersion
:
cli
.
apiVersion
ForResource
(
resourceAuthCode
)
,
APIVersion
:
cli
.
apiVersion
,
},
ObjectMeta
:
k8sapi
.
ObjectMeta
{
Name
:
a
.
ID
,
...
...
@@ -346,7 +404,7 @@ func (cli *client) fromStorageKeys(keys storage.Keys) Keys {
return
Keys
{
TypeMeta
:
k8sapi
.
TypeMeta
{
Kind
:
kindKeys
,
APIVersion
:
cli
.
apiVersion
ForResource
(
resourceKeys
)
,
APIVersion
:
cli
.
apiVersion
,
},
ObjectMeta
:
k8sapi
.
ObjectMeta
{
Name
:
keysName
,
...
...
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