api: adding a gRPC call for listing refresh tokens.
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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,
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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(),
|
||||
|
Reference in New Issue
Block a user