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
1ec19d4f
Commit
1ec19d4f
authored
Feb 14, 2017
by
rithu john
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
api: adding a gRPC call for revoking refresh tokens.
parent
b119ffdd
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
148 additions
and
4 deletions
+148
-4
api.pb.go
api/api.pb.go
+0
-0
api.proto
api/api.proto
+18
-1
api.go
server/api.go
+39
-3
api_test.go
server/api_test.go
+91
-0
No files found.
api/api.pb.go
View file @
1ec19d4f
This diff is collapsed.
Click to expand it.
api/api.proto
View file @
1ec19d4f
...
...
@@ -30,7 +30,7 @@ message DeleteClientReq {
string
id
=
1
;
}
// DeleteClientResp determines if the.
// DeleteClientResp determines if the
client is deleted successfully
.
message
DeleteClientResp
{
bool
not_found
=
1
;
}
...
...
@@ -120,6 +120,19 @@ message ListRefreshResp {
repeated
RefreshTokenRef
refresh_tokens
=
1
;
}
// RevokeRefreshReq is a request to revoke the refresh token of the user-client pair.
message
RevokeRefreshReq
{
// The "sub" claim returned in the ID Token.
string
user_id
=
1
;
string
client_id
=
2
;
}
// RevokeRefreshResp determines if the refresh token is revoked successfully.
message
RevokeRefreshResp
{
// Set to true is refresh token was not found and token could not be revoked.
bool
not_found
=
1
;
}
// Dex represents the dex gRPC service.
service
Dex
{
// CreateClient creates a client.
...
...
@@ -138,4 +151,8 @@ service Dex {
rpc
GetVersion
(
VersionReq
)
returns
(
VersionResp
)
{};
// ListRefresh lists all the refresh token entries for a particular user.
rpc
ListRefresh
(
ListRefreshReq
)
returns
(
ListRefreshResp
)
{};
// RevokeRefresh revokes the refresh token for the provided user-client pair.
//
// Note that each user-client pair can have only one refresh token at a time.
rpc
RevokeRefresh
(
RevokeRefreshReq
)
returns
(
RevokeRefreshResp
)
{};
}
server/api.go
View file @
1ec19d4f
...
...
@@ -16,7 +16,7 @@ import (
// apiVersion increases every time a new call is added to the API. Clients should use this info
// to determine if the server supports specific features.
const
apiVersion
=
0
const
apiVersion
=
1
// NewAPI returns a server which implements the gRPC API interface.
func
NewAPI
(
s
storage
.
Storage
,
logger
logrus
.
FieldLogger
)
api
.
DexServer
{
...
...
@@ -204,13 +204,13 @@ func (d dexAPI) ListRefresh(ctx context.Context, req *api.ListRefreshReq) (*api.
id
:=
new
(
internal
.
IDTokenSubject
)
if
err
:=
internal
.
Unmarshal
(
req
.
UserId
,
id
);
err
!=
nil
{
d
.
logger
.
Errorf
(
"api: failed to unmarshal ID Token subject: %v"
,
err
)
return
nil
,
fmt
.
Errorf
(
"unmarshal ID Token subject: %v"
,
err
)
return
nil
,
err
}
offlineSessions
,
err
:=
d
.
s
.
GetOfflineSessions
(
id
.
UserId
,
id
.
ConnId
)
if
err
!=
nil
{
d
.
logger
.
Errorf
(
"api: failed to list refresh tokens: %v"
,
err
)
return
nil
,
fmt
.
Errorf
(
"list refresh tokens: %v"
,
err
)
return
nil
,
err
}
var
refreshTokenRefs
[]
*
api
.
RefreshTokenRef
...
...
@@ -228,3 +228,39 @@ func (d dexAPI) ListRefresh(ctx context.Context, req *api.ListRefreshReq) (*api.
RefreshTokens
:
refreshTokenRefs
,
},
nil
}
func
(
d
dexAPI
)
RevokeRefresh
(
ctx
context
.
Context
,
req
*
api
.
RevokeRefreshReq
)
(
*
api
.
RevokeRefreshResp
,
error
)
{
id
:=
new
(
internal
.
IDTokenSubject
)
if
err
:=
internal
.
Unmarshal
(
req
.
UserId
,
id
);
err
!=
nil
{
d
.
logger
.
Errorf
(
"api: failed to unmarshal ID Token subject: %v"
,
err
)
return
nil
,
err
}
var
refreshID
string
updater
:=
func
(
old
storage
.
OfflineSessions
)
(
storage
.
OfflineSessions
,
error
)
{
if
refreshID
=
old
.
Refresh
[
req
.
ClientId
]
.
ID
;
refreshID
==
""
{
return
old
,
fmt
.
Errorf
(
"user does not have a refresh token for the client = %s"
,
req
.
ClientId
)
}
// Remove entry from Refresh list of the OfflineSession object.
delete
(
old
.
Refresh
,
req
.
ClientId
)
return
old
,
nil
}
if
err
:=
d
.
s
.
UpdateOfflineSessions
(
id
.
UserId
,
id
.
ConnId
,
updater
);
err
!=
nil
{
if
err
==
storage
.
ErrNotFound
{
return
&
api
.
RevokeRefreshResp
{
NotFound
:
true
},
nil
}
d
.
logger
.
Errorf
(
"api: failed to update offline session object: %v"
,
err
)
return
nil
,
err
}
// Delete the refresh token from the storage
if
err
:=
d
.
s
.
DeleteRefresh
(
refreshID
);
err
!=
nil
{
d
.
logger
.
Errorf
(
"failed to delete refresh token: %v"
,
err
)
return
nil
,
err
}
return
&
api
.
RevokeRefreshResp
{},
nil
}
server/api_test.go
View file @
1ec19d4f
...
...
@@ -4,9 +4,12 @@ import (
"context"
"os"
"testing"
"time"
"github.com/Sirupsen/logrus"
"github.com/coreos/dex/api"
"github.com/coreos/dex/server/internal"
"github.com/coreos/dex/storage"
"github.com/coreos/dex/storage/memory"
)
...
...
@@ -65,3 +68,91 @@ func TestPassword(t *testing.T) {
}
}
// Attempts to list and revoke an exisiting refresh token.
func
TestRefreshToken
(
t
*
testing
.
T
)
{
logger
:=
&
logrus
.
Logger
{
Out
:
os
.
Stderr
,
Formatter
:
&
logrus
.
TextFormatter
{
DisableColors
:
true
},
Level
:
logrus
.
DebugLevel
,
}
s
:=
memory
.
New
(
logger
)
serv
:=
NewAPI
(
s
,
logger
)
ctx
:=
context
.
Background
()
// Creating a storage with an existing refresh token and offline session for the user.
id
:=
storage
.
NewID
()
r
:=
storage
.
RefreshToken
{
ID
:
id
,
Token
:
"bar"
,
Nonce
:
"foo"
,
ClientID
:
"client_id"
,
ConnectorID
:
"client_secret"
,
Scopes
:
[]
string
{
"openid"
,
"email"
,
"profile"
},
CreatedAt
:
time
.
Now
()
.
UTC
()
.
Round
(
time
.
Millisecond
),
LastUsed
:
time
.
Now
()
.
UTC
()
.
Round
(
time
.
Millisecond
),
Claims
:
storage
.
Claims
{
UserID
:
"1"
,
Username
:
"jane"
,
Email
:
"jane.doe@example.com"
,
EmailVerified
:
true
,
Groups
:
[]
string
{
"a"
,
"b"
},
},
ConnectorData
:
[]
byte
(
`{"some":"data"}`
),
}
if
err
:=
s
.
CreateRefresh
(
r
);
err
!=
nil
{
t
.
Fatalf
(
"create refresh token: %v"
,
err
)
}
tokenRef
:=
storage
.
RefreshTokenRef
{
ID
:
r
.
ID
,
ClientID
:
r
.
ClientID
,
CreatedAt
:
r
.
CreatedAt
,
LastUsed
:
r
.
LastUsed
,
}
session
:=
storage
.
OfflineSessions
{
UserID
:
r
.
Claims
.
UserID
,
ConnID
:
r
.
ConnectorID
,
Refresh
:
make
(
map
[
string
]
*
storage
.
RefreshTokenRef
),
}
session
.
Refresh
[
tokenRef
.
ClientID
]
=
&
tokenRef
if
err
:=
s
.
CreateOfflineSessions
(
session
);
err
!=
nil
{
t
.
Fatalf
(
"create offline session: %v"
,
err
)
}
subjectString
,
err
:=
internal
.
Marshal
(
&
internal
.
IDTokenSubject
{
UserId
:
r
.
Claims
.
UserID
,
ConnId
:
r
.
ConnectorID
,
})
if
err
!=
nil
{
t
.
Errorf
(
"failed to marshal offline session ID: %v"
,
err
)
}
//Testing the api.
listReq
:=
api
.
ListRefreshReq
{
UserId
:
subjectString
,
}
if
_
,
err
:=
serv
.
ListRefresh
(
ctx
,
&
listReq
);
err
!=
nil
{
t
.
Fatalf
(
"Unable to list refresh tokens for user: %v"
,
err
)
}
revokeReq
:=
api
.
RevokeRefreshReq
{
UserId
:
subjectString
,
ClientId
:
r
.
ClientID
,
}
resp
,
err
:=
serv
.
RevokeRefresh
(
ctx
,
&
revokeReq
)
if
err
!=
nil
||
resp
.
NotFound
{
t
.
Fatalf
(
"Unable to revoke refresh tokens for user: %v"
,
err
)
}
if
resp
,
_
:=
serv
.
ListRefresh
(
ctx
,
&
listReq
);
len
(
resp
.
RefreshTokens
)
!=
0
{
t
.
Fatalf
(
"Refresh token returned inspite of revoking it."
)
}
}
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