api: adding a gRPC call for listing refresh tokens.

This commit is contained in:
rithu john
2017-02-10 11:33:54 -08:00
parent 53e383670a
commit d201e49248
7 changed files with 229 additions and 51 deletions

View File

@@ -9,6 +9,7 @@ import (
"github.com/Sirupsen/logrus"
"github.com/coreos/dex/api"
"github.com/coreos/dex/server/internal"
"github.com/coreos/dex/storage"
"github.com/coreos/dex/version"
)
@@ -198,3 +199,32 @@ func (d dexAPI) ListPasswords(ctx context.Context, req *api.ListPasswordReq) (*a
}, nil
}
func (d dexAPI) ListRefresh(ctx context.Context, req *api.ListRefreshReq) (*api.ListRefreshResp, 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, fmt.Errorf("unmarshal ID Token subject: %v", 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)
}
var refreshTokenRefs []*api.RefreshTokenRef
for _, session := range offlineSessions.Refresh {
r := api.RefreshTokenRef{
Id: session.ID,
ClientId: session.ClientID,
CreatedAt: session.CreatedAt.String(),
LastUsed: session.LastUsed.String(),
}
refreshTokenRefs = append(refreshTokenRefs, &r)
}
return &api.ListRefreshResp{
RefreshTokens: refreshTokenRefs,
}, nil
}

View File

@@ -510,7 +510,7 @@ func (s *Server) sendCodeResponse(w http.ResponseWriter, r *http.Request, authRe
case responseTypeIDToken:
implicitOrHybrid = true
var err error
idToken, idTokenExpiry, err = s.newIDToken(authReq.ClientID, authReq.Claims, authReq.Scopes, authReq.Nonce, accessToken)
idToken, idTokenExpiry, err = s.newIDToken(authReq.ClientID, authReq.Claims, authReq.Scopes, authReq.Nonce, accessToken, authReq.ConnectorID)
if err != nil {
s.logger.Errorf("failed to create ID token: %v", err)
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
@@ -632,7 +632,7 @@ func (s *Server) handleAuthCode(w http.ResponseWriter, r *http.Request, client s
}
accessToken := storage.NewID()
idToken, expiry, err := s.newIDToken(client.ID, authCode.Claims, authCode.Scopes, authCode.Nonce, accessToken)
idToken, expiry, err := s.newIDToken(client.ID, authCode.Claims, authCode.Scopes, authCode.Nonce, accessToken, authCode.ConnectorID)
if err != nil {
s.logger.Errorf("failed to create ID token: %v", err)
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
@@ -866,7 +866,7 @@ func (s *Server) handleRefreshToken(w http.ResponseWriter, r *http.Request, clie
}
accessToken := storage.NewID()
idToken, expiry, err := s.newIDToken(client.ID, claims, scopes, refresh.Nonce, accessToken)
idToken, expiry, err := s.newIDToken(client.ID, claims, scopes, refresh.Nonce, accessToken, refresh.ConnectorID)
if err != nil {
s.logger.Errorf("failed to create ID token: %v", err)
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)

View File

@@ -12,6 +12,7 @@ It is generated from these files:
It has these top-level messages:
RefreshToken
IDTokenSubject
*/
package internal
@@ -41,19 +42,35 @@ func (m *RefreshToken) String() string { return proto.CompactTextStri
func (*RefreshToken) ProtoMessage() {}
func (*RefreshToken) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
// IDTokenSubject represents both the userID and connID which is returned
// as the "sub" claim in the ID Token.
type IDTokenSubject struct {
UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"`
ConnId string `protobuf:"bytes,2,opt,name=conn_id,json=connId" json:"conn_id,omitempty"`
}
func (m *IDTokenSubject) Reset() { *m = IDTokenSubject{} }
func (m *IDTokenSubject) String() string { return proto.CompactTextString(m) }
func (*IDTokenSubject) ProtoMessage() {}
func (*IDTokenSubject) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
func init() {
proto.RegisterType((*RefreshToken)(nil), "internal.RefreshToken")
proto.RegisterType((*IDTokenSubject)(nil), "internal.IDTokenSubject")
}
func init() { proto.RegisterFile("server/internal/types.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 112 bytes of a gzipped FileDescriptorProto
// 157 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0x92, 0x2e, 0x4e, 0x2d, 0x2a,
0x4b, 0x2d, 0xd2, 0xcf, 0xcc, 0x2b, 0x49, 0x2d, 0xca, 0x4b, 0xcc, 0xd1, 0x2f, 0xa9, 0x2c, 0x48,
0x2d, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x80, 0x89, 0x2a, 0x39, 0x73, 0xf1, 0x04,
0xa5, 0xa6, 0x15, 0xa5, 0x16, 0x67, 0x84, 0xe4, 0x67, 0xa7, 0xe6, 0x09, 0xc9, 0x72, 0x71, 0x15,
0x41, 0xf8, 0xf1, 0x99, 0x29, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x9c, 0x41, 0x9c, 0x50, 0x11, 0xcf,
0x14, 0x21, 0x11, 0x2e, 0xd6, 0x12, 0x90, 0x3a, 0x09, 0x26, 0xb0, 0x0c, 0x84, 0x93, 0xc4, 0x06,
0x36, 0xd5, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x9b, 0xd0, 0x5a, 0x1d, 0x74, 0x00, 0x00, 0x00,
0x14, 0x21, 0x11, 0x2e, 0xd6, 0x12, 0x90, 0x3a, 0x09, 0x26, 0xb0, 0x0c, 0x84, 0xa3, 0xe4, 0xc4,
0xc5, 0xe7, 0xe9, 0x02, 0xd6, 0x1f, 0x5c, 0x9a, 0x94, 0x95, 0x9a, 0x5c, 0x22, 0x24, 0xce, 0xc5,
0x5e, 0x5a, 0x9c, 0x5a, 0x84, 0x30, 0x83, 0x0d, 0xc4, 0xf5, 0x4c, 0x01, 0x49, 0x24, 0xe7, 0xe7,
0xe5, 0x81, 0x24, 0x20, 0x46, 0xb0, 0x81, 0xb8, 0x9e, 0x29, 0x49, 0x6c, 0x60, 0x97, 0x19, 0x03,
0x02, 0x00, 0x00, 0xff, 0xff, 0x13, 0xfe, 0x01, 0x37, 0xb8, 0x00, 0x00, 0x00,
}

View File

@@ -8,3 +8,10 @@ message RefreshToken {
string refresh_id = 1;
string token = 2;
}
// IDTokenSubject represents both the userID and connID which is returned
// as the "sub" claim in the ID Token.
message IDTokenSubject {
string user_id = 1;
string conn_id = 2;
}

View File

@@ -21,6 +21,7 @@ import (
jose "gopkg.in/square/go-jose.v2"
"github.com/coreos/dex/connector"
"github.com/coreos/dex/server/internal"
"github.com/coreos/dex/storage"
)
@@ -246,7 +247,7 @@ type idTokenClaims struct {
Name string `json:"name,omitempty"`
}
func (s *Server) newIDToken(clientID string, claims storage.Claims, scopes []string, nonce, accessToken string) (idToken string, expiry time.Time, err error) {
func (s *Server) newIDToken(clientID string, claims storage.Claims, scopes []string, nonce, accessToken, connID string) (idToken string, expiry time.Time, err error) {
keys, err := s.storage.GetKeys()
if err != nil {
s.logger.Errorf("Failed to get keys: %v", err)
@@ -265,9 +266,20 @@ func (s *Server) newIDToken(clientID string, claims storage.Claims, scopes []str
issuedAt := s.now()
expiry = issuedAt.Add(s.idTokensValidFor)
sub := &internal.IDTokenSubject{
UserId: claims.UserID,
ConnId: connID,
}
subjectString, err := internal.Marshal(sub)
if err != nil {
s.logger.Errorf("failed to marshal offline session ID: %v", err)
return "", expiry, fmt.Errorf("failed to marshal offline session ID: %v", err)
}
tok := idTokenClaims{
Issuer: s.issuerURL.String(),
Subject: claims.UserID,
Subject: subjectString,
Nonce: nonce,
Expiry: expiry.Unix(),
IssuedAt: issuedAt.Unix(),