|
|
|
|
@ -3,7 +3,6 @@ package server
|
|
|
|
|
import ( |
|
|
|
|
"encoding/json" |
|
|
|
|
"fmt" |
|
|
|
|
"log" |
|
|
|
|
"net/http" |
|
|
|
|
"net/url" |
|
|
|
|
"path" |
|
|
|
|
@ -42,7 +41,7 @@ func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
|
|
t := s.now().Sub(start) |
|
|
|
|
if err != nil { |
|
|
|
|
log.Printf("Storage health check failed: %v", err) |
|
|
|
|
s.logger.Errorf("Storage health check failed: %v", err) |
|
|
|
|
http.Error(w, "Health check failed", http.StatusInternalServerError) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
@ -53,13 +52,13 @@ func (s *Server) handlePublicKeys(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
// TODO(ericchiang): Cache this.
|
|
|
|
|
keys, err := s.storage.GetKeys() |
|
|
|
|
if err != nil { |
|
|
|
|
log.Printf("failed to get keys: %v", err) |
|
|
|
|
s.logger.Errorf("failed to get keys: %v", err) |
|
|
|
|
http.Error(w, "Internal server error", http.StatusInternalServerError) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if keys.SigningKeyPub == nil { |
|
|
|
|
log.Printf("No public keys found.") |
|
|
|
|
s.logger.Errorf("No public keys found.") |
|
|
|
|
http.Error(w, "Internal server error", http.StatusInternalServerError) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
@ -74,7 +73,7 @@ func (s *Server) handlePublicKeys(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
|
|
data, err := json.MarshalIndent(jwks, "", " ") |
|
|
|
|
if err != nil { |
|
|
|
|
log.Printf("failed to marshal discovery data: %v", err) |
|
|
|
|
s.logger.Errorf("failed to marshal discovery data: %v", err) |
|
|
|
|
http.Error(w, "Internal server error", http.StatusInternalServerError) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
@ -137,14 +136,14 @@ func (s *Server) discoveryHandler() (http.HandlerFunc, error) {
|
|
|
|
|
|
|
|
|
|
// handleAuthorization handles the OAuth2 auth endpoint.
|
|
|
|
|
func (s *Server) handleAuthorization(w http.ResponseWriter, r *http.Request) { |
|
|
|
|
authReq, err := parseAuthorizationRequest(s.storage, s.supportedResponseTypes, r) |
|
|
|
|
authReq, err := s.parseAuthorizationRequest(s.supportedResponseTypes, r) |
|
|
|
|
if err != nil { |
|
|
|
|
s.renderError(w, http.StatusInternalServerError, err.Type, err.Description) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
authReq.Expiry = s.now().Add(time.Minute * 30) |
|
|
|
|
if err := s.storage.CreateAuthRequest(authReq); err != nil { |
|
|
|
|
log.Printf("Failed to create authorization request: %v", err) |
|
|
|
|
s.logger.Errorf("Failed to create authorization request: %v", err) |
|
|
|
|
s.renderError(w, http.StatusInternalServerError, errServerError, "") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
@ -166,7 +165,9 @@ func (s *Server) handleAuthorization(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
i++ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
s.templates.login(w, connectorInfos, authReq.ID) |
|
|
|
|
if err := s.templates.login(w, connectorInfos, authReq.ID); err != nil { |
|
|
|
|
s.logger.Errorf("Server template error: %v", err) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (s *Server) handleConnectorLogin(w http.ResponseWriter, r *http.Request) { |
|
|
|
|
@ -181,8 +182,8 @@ func (s *Server) handleConnectorLogin(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
|
|
authReq, err := s.storage.GetAuthRequest(authReqID) |
|
|
|
|
if err != nil { |
|
|
|
|
log.Printf("Failed to get auth request: %v", err) |
|
|
|
|
s.renderError(w, http.StatusInternalServerError, errServerError, "") |
|
|
|
|
s.logger.Errorf("Failed to get auth request: %v", err) |
|
|
|
|
s.renderError(w, http.StatusInternalServerError, errServerError, "Connector Login Error") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
scopes := parseScopes(authReq.Scopes) |
|
|
|
|
@ -195,8 +196,8 @@ func (s *Server) handleConnectorLogin(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
return a, nil |
|
|
|
|
} |
|
|
|
|
if err := s.storage.UpdateAuthRequest(authReqID, updater); err != nil { |
|
|
|
|
log.Printf("Failed to set connector ID on auth request: %v", err) |
|
|
|
|
s.renderError(w, http.StatusInternalServerError, errServerError, "") |
|
|
|
|
s.logger.Errorf("Failed to set connector ID on auth request: %v", err) |
|
|
|
|
s.renderError(w, http.StatusInternalServerError, errServerError, "Connector Login Error") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -207,13 +208,15 @@ func (s *Server) handleConnectorLogin(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
// TODO(ericchiang): Is this appropriate or should we also be using a nonce?
|
|
|
|
|
callbackURL, err := conn.LoginURL(scopes, s.absURL("/callback"), authReqID) |
|
|
|
|
if err != nil { |
|
|
|
|
log.Printf("Connector %q returned error when creating callback: %v", connID, err) |
|
|
|
|
s.renderError(w, http.StatusInternalServerError, errServerError, "") |
|
|
|
|
s.logger.Errorf("Connector %q returned error when creating callback: %v", connID, err) |
|
|
|
|
s.renderError(w, http.StatusInternalServerError, errServerError, "Connector Login Error") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
http.Redirect(w, r, callbackURL, http.StatusFound) |
|
|
|
|
case connector.PasswordConnector: |
|
|
|
|
s.templates.password(w, authReqID, r.URL.String(), "", false) |
|
|
|
|
if err := s.templates.password(w, authReqID, r.URL.String(), "", false); err != nil { |
|
|
|
|
s.logger.Errorf("Server template error: %v", err) |
|
|
|
|
} |
|
|
|
|
default: |
|
|
|
|
s.notFound(w, r) |
|
|
|
|
} |
|
|
|
|
@ -229,18 +232,20 @@ func (s *Server) handleConnectorLogin(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
|
|
identity, ok, err := passwordConnector.Login(r.Context(), scopes, username, password) |
|
|
|
|
if err != nil { |
|
|
|
|
log.Printf("Failed to login user: %v", err) |
|
|
|
|
s.renderError(w, http.StatusInternalServerError, errServerError, "") |
|
|
|
|
s.logger.Errorf("Failed to login user: %v", err) |
|
|
|
|
s.renderError(w, http.StatusInternalServerError, errServerError, "Connector Login Error") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
if !ok { |
|
|
|
|
s.templates.password(w, authReqID, r.URL.String(), username, true) |
|
|
|
|
if err := s.templates.password(w, authReqID, r.URL.String(), username, true); err != nil { |
|
|
|
|
s.logger.Errorf("Server template error: %v", err) |
|
|
|
|
} |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
redirectURL, err := s.finalizeLogin(identity, authReq, conn.Connector) |
|
|
|
|
if err != nil { |
|
|
|
|
log.Printf("Failed to finalize login: %v", err) |
|
|
|
|
s.renderError(w, http.StatusInternalServerError, errServerError, "") |
|
|
|
|
s.logger.Errorf("Failed to finalize login: %v", err) |
|
|
|
|
s.renderError(w, http.StatusInternalServerError, errServerError, "Connector Login Error") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -260,17 +265,17 @@ func (s *Server) handleConnectorCallback(w http.ResponseWriter, r *http.Request)
|
|
|
|
|
// Section: "3.4.3 RelayState"
|
|
|
|
|
state := r.URL.Query().Get("state") |
|
|
|
|
if state == "" { |
|
|
|
|
s.renderError(w, http.StatusBadRequest, errInvalidRequest, "no 'state' parameter provided") |
|
|
|
|
s.renderError(w, http.StatusBadRequest, errInvalidRequest, "No 'state' parameter provided.") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
authReq, err := s.storage.GetAuthRequest(state) |
|
|
|
|
if err != nil { |
|
|
|
|
if err == storage.ErrNotFound { |
|
|
|
|
s.renderError(w, http.StatusBadRequest, errInvalidRequest, "invalid 'state' parameter provided") |
|
|
|
|
s.renderError(w, http.StatusBadRequest, errInvalidRequest, "Invalid 'state' parameter provided.") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
log.Printf("Failed to get auth request: %v", err) |
|
|
|
|
s.logger.Errorf("Failed to get auth request: %v", err) |
|
|
|
|
s.renderError(w, http.StatusInternalServerError, errServerError, "") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
@ -288,14 +293,14 @@ func (s *Server) handleConnectorCallback(w http.ResponseWriter, r *http.Request)
|
|
|
|
|
|
|
|
|
|
identity, err := callbackConnector.HandleCallback(parseScopes(authReq.Scopes), r) |
|
|
|
|
if err != nil { |
|
|
|
|
log.Printf("Failed to authenticate: %v", err) |
|
|
|
|
s.logger.Errorf("Failed to authenticate: %v", err) |
|
|
|
|
s.renderError(w, http.StatusInternalServerError, errServerError, "") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
redirectURL, err := s.finalizeLogin(identity, authReq, conn.Connector) |
|
|
|
|
if err != nil { |
|
|
|
|
log.Printf("Failed to finalize login: %v", err) |
|
|
|
|
s.logger.Errorf("Failed to finalize login: %v", err) |
|
|
|
|
s.renderError(w, http.StatusInternalServerError, errServerError, "") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
@ -327,12 +332,12 @@ func (s *Server) finalizeLogin(identity connector.Identity, authReq storage.Auth
|
|
|
|
|
func (s *Server) handleApproval(w http.ResponseWriter, r *http.Request) { |
|
|
|
|
authReq, err := s.storage.GetAuthRequest(r.FormValue("req")) |
|
|
|
|
if err != nil { |
|
|
|
|
log.Printf("Failed to get auth request: %v", err) |
|
|
|
|
s.logger.Errorf("Failed to get auth request: %v", err) |
|
|
|
|
s.renderError(w, http.StatusInternalServerError, errServerError, "") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
if !authReq.LoggedIn { |
|
|
|
|
log.Printf("Auth request does not have an identity for approval") |
|
|
|
|
s.logger.Errorf("Auth request does not have an identity for approval") |
|
|
|
|
s.renderError(w, http.StatusInternalServerError, errServerError, "") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
@ -345,11 +350,13 @@ func (s *Server) handleApproval(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
} |
|
|
|
|
client, err := s.storage.GetClient(authReq.ClientID) |
|
|
|
|
if err != nil { |
|
|
|
|
log.Printf("Failed to get client %q: %v", authReq.ClientID, err) |
|
|
|
|
s.logger.Errorf("Failed to get client %q: %v", authReq.ClientID, err) |
|
|
|
|
s.renderError(w, http.StatusInternalServerError, errServerError, "") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
s.templates.approval(w, authReq.ID, authReq.Claims.Username, client.Name, authReq.Scopes) |
|
|
|
|
if err := s.templates.approval(w, authReq.ID, authReq.Claims.Username, client.Name, authReq.Scopes); err != nil { |
|
|
|
|
s.logger.Errorf("Server template error: %v", err) |
|
|
|
|
} |
|
|
|
|
case "POST": |
|
|
|
|
if r.FormValue("approval") != "approve" { |
|
|
|
|
s.renderError(w, http.StatusInternalServerError, "approval rejected", "") |
|
|
|
|
@ -367,7 +374,7 @@ func (s *Server) sendCodeResponse(w http.ResponseWriter, r *http.Request, authRe
|
|
|
|
|
|
|
|
|
|
if err := s.storage.DeleteAuthRequest(authReq.ID); err != nil { |
|
|
|
|
if err != storage.ErrNotFound { |
|
|
|
|
log.Printf("Failed to delete authorization request: %v", err) |
|
|
|
|
s.logger.Errorf("Failed to delete authorization request: %v", err) |
|
|
|
|
s.renderError(w, http.StatusInternalServerError, errServerError, "") |
|
|
|
|
} else { |
|
|
|
|
s.renderError(w, http.StatusBadRequest, errInvalidRequest, "Authorization request has already been completed.") |
|
|
|
|
@ -396,21 +403,23 @@ func (s *Server) sendCodeResponse(w http.ResponseWriter, r *http.Request, authRe
|
|
|
|
|
ConnectorData: authReq.ConnectorData, |
|
|
|
|
} |
|
|
|
|
if err := s.storage.CreateAuthCode(code); err != nil { |
|
|
|
|
log.Printf("Failed to create auth code: %v", err) |
|
|
|
|
s.logger.Errorf("Failed to create auth code: %v", err) |
|
|
|
|
s.renderError(w, http.StatusInternalServerError, errServerError, "") |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if authReq.RedirectURI == redirectURIOOB { |
|
|
|
|
s.templates.oob(w, code.ID) |
|
|
|
|
if err := s.templates.oob(w, code.ID); err != nil { |
|
|
|
|
s.logger.Errorf("Server template error: %v", err) |
|
|
|
|
} |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
q.Set("code", code.ID) |
|
|
|
|
case responseTypeToken: |
|
|
|
|
idToken, expiry, err := s.newIDToken(authReq.ClientID, authReq.Claims, authReq.Scopes, authReq.Nonce) |
|
|
|
|
if err != nil { |
|
|
|
|
log.Printf("failed to create ID token: %v", err) |
|
|
|
|
tokenErr(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
s.logger.Errorf("failed to create ID token: %v", err) |
|
|
|
|
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
v := url.Values{} |
|
|
|
|
@ -433,11 +442,11 @@ func (s *Server) handleToken(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
if ok { |
|
|
|
|
var err error |
|
|
|
|
if clientID, err = url.QueryUnescape(clientID); err != nil { |
|
|
|
|
tokenErr(w, errInvalidRequest, "client_id improperly encoded", http.StatusBadRequest) |
|
|
|
|
s.tokenErrHelper(w, errInvalidRequest, "client_id improperly encoded", http.StatusBadRequest) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
if clientSecret, err = url.QueryUnescape(clientSecret); err != nil { |
|
|
|
|
tokenErr(w, errInvalidRequest, "client_secret improperly encoded", http.StatusBadRequest) |
|
|
|
|
s.tokenErrHelper(w, errInvalidRequest, "client_secret improperly encoded", http.StatusBadRequest) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
@ -448,15 +457,15 @@ func (s *Server) handleToken(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
client, err := s.storage.GetClient(clientID) |
|
|
|
|
if err != nil { |
|
|
|
|
if err != storage.ErrNotFound { |
|
|
|
|
log.Printf("failed to get client: %v", err) |
|
|
|
|
tokenErr(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
s.logger.Errorf("failed to get client: %v", err) |
|
|
|
|
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
} else { |
|
|
|
|
tokenErr(w, errInvalidClient, "Invalid client credentials.", http.StatusUnauthorized) |
|
|
|
|
s.tokenErrHelper(w, errInvalidClient, "Invalid client credentials.", http.StatusUnauthorized) |
|
|
|
|
} |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
if client.Secret != clientSecret { |
|
|
|
|
tokenErr(w, errInvalidClient, "Invalid client credentials.", http.StatusUnauthorized) |
|
|
|
|
s.tokenErrHelper(w, errInvalidClient, "Invalid client credentials.", http.StatusUnauthorized) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -467,7 +476,7 @@ func (s *Server) handleToken(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
case grantTypeRefreshToken: |
|
|
|
|
s.handleRefreshToken(w, r, client) |
|
|
|
|
default: |
|
|
|
|
tokenErr(w, errInvalidGrant, "", http.StatusBadRequest) |
|
|
|
|
s.tokenErrHelper(w, errInvalidGrant, "", http.StatusBadRequest) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -479,29 +488,29 @@ func (s *Server) handleAuthCode(w http.ResponseWriter, r *http.Request, client s
|
|
|
|
|
authCode, err := s.storage.GetAuthCode(code) |
|
|
|
|
if err != nil || s.now().After(authCode.Expiry) || authCode.ClientID != client.ID { |
|
|
|
|
if err != storage.ErrNotFound { |
|
|
|
|
log.Printf("failed to get auth code: %v", err) |
|
|
|
|
tokenErr(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
s.logger.Errorf("failed to get auth code: %v", err) |
|
|
|
|
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
} else { |
|
|
|
|
tokenErr(w, errInvalidRequest, "Invalid or expired code parameter.", http.StatusBadRequest) |
|
|
|
|
s.tokenErrHelper(w, errInvalidRequest, "Invalid or expired code parameter.", http.StatusBadRequest) |
|
|
|
|
} |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if authCode.RedirectURI != redirectURI { |
|
|
|
|
tokenErr(w, errInvalidRequest, "redirect_uri did not match URI from initial request.", http.StatusBadRequest) |
|
|
|
|
s.tokenErrHelper(w, errInvalidRequest, "redirect_uri did not match URI from initial request.", http.StatusBadRequest) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
idToken, expiry, err := s.newIDToken(client.ID, authCode.Claims, authCode.Scopes, authCode.Nonce) |
|
|
|
|
if err != nil { |
|
|
|
|
log.Printf("failed to create ID token: %v", err) |
|
|
|
|
tokenErr(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
s.logger.Errorf("failed to create ID token: %v", err) |
|
|
|
|
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if err := s.storage.DeleteAuthCode(code); err != nil { |
|
|
|
|
log.Printf("failed to delete auth code: %v", err) |
|
|
|
|
tokenErr(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
s.logger.Errorf("failed to delete auth code: %v", err) |
|
|
|
|
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -525,8 +534,8 @@ func (s *Server) handleAuthCode(w http.ResponseWriter, r *http.Request, client s
|
|
|
|
|
ConnectorData: authCode.ConnectorData, |
|
|
|
|
} |
|
|
|
|
if err := s.storage.CreateRefresh(refresh); err != nil { |
|
|
|
|
log.Printf("failed to create refresh token: %v", err) |
|
|
|
|
tokenErr(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
s.logger.Errorf("failed to create refresh token: %v", err) |
|
|
|
|
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
refreshToken = refresh.RefreshToken |
|
|
|
|
@ -539,17 +548,17 @@ func (s *Server) handleRefreshToken(w http.ResponseWriter, r *http.Request, clie
|
|
|
|
|
code := r.PostFormValue("refresh_token") |
|
|
|
|
scope := r.PostFormValue("scope") |
|
|
|
|
if code == "" { |
|
|
|
|
tokenErr(w, errInvalidRequest, "No refresh token in request.", http.StatusBadRequest) |
|
|
|
|
s.tokenErrHelper(w, errInvalidRequest, "No refresh token in request.", http.StatusBadRequest) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
refresh, err := s.storage.GetRefresh(code) |
|
|
|
|
if err != nil || refresh.ClientID != client.ID { |
|
|
|
|
if err != storage.ErrNotFound { |
|
|
|
|
log.Printf("failed to get auth code: %v", err) |
|
|
|
|
tokenErr(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
s.logger.Errorf("failed to get auth code: %v", err) |
|
|
|
|
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
} else { |
|
|
|
|
tokenErr(w, errInvalidRequest, "Refresh token is invalid or has already been claimed by another client.", http.StatusBadRequest) |
|
|
|
|
s.tokenErrHelper(w, errInvalidRequest, "Refresh token is invalid or has already been claimed by another client.", http.StatusBadRequest) |
|
|
|
|
} |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
@ -579,7 +588,7 @@ func (s *Server) handleRefreshToken(w http.ResponseWriter, r *http.Request, clie
|
|
|
|
|
|
|
|
|
|
if len(unauthorizedScopes) > 0 { |
|
|
|
|
msg := fmt.Sprintf("Requested scopes contain unauthorized scope(s): %q.", unauthorizedScopes) |
|
|
|
|
tokenErr(w, errInvalidRequest, msg, http.StatusBadRequest) |
|
|
|
|
s.tokenErrHelper(w, errInvalidRequest, msg, http.StatusBadRequest) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
scopes = requestedScopes |
|
|
|
|
@ -587,8 +596,8 @@ func (s *Server) handleRefreshToken(w http.ResponseWriter, r *http.Request, clie
|
|
|
|
|
|
|
|
|
|
conn, ok := s.connectors[refresh.ConnectorID] |
|
|
|
|
if !ok { |
|
|
|
|
log.Printf("connector ID not found: %q", refresh.ConnectorID) |
|
|
|
|
tokenErr(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
s.logger.Errorf("connector ID not found: %q", refresh.ConnectorID) |
|
|
|
|
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -608,8 +617,8 @@ func (s *Server) handleRefreshToken(w http.ResponseWriter, r *http.Request, clie
|
|
|
|
|
} |
|
|
|
|
ident, err := refreshConn.Refresh(r.Context(), parseScopes(scopes), ident) |
|
|
|
|
if err != nil { |
|
|
|
|
log.Printf("failed to refresh identity: %v", err) |
|
|
|
|
tokenErr(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
s.logger.Errorf("failed to refresh identity: %v", err) |
|
|
|
|
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -625,22 +634,22 @@ func (s *Server) handleRefreshToken(w http.ResponseWriter, r *http.Request, clie
|
|
|
|
|
|
|
|
|
|
idToken, expiry, err := s.newIDToken(client.ID, refresh.Claims, scopes, refresh.Nonce) |
|
|
|
|
if err != nil { |
|
|
|
|
log.Printf("failed to create ID token: %v", err) |
|
|
|
|
tokenErr(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
s.logger.Errorf("failed to create ID token: %v", err) |
|
|
|
|
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Refresh tokens are claimed exactly once. Delete the current token and
|
|
|
|
|
// create a new one.
|
|
|
|
|
if err := s.storage.DeleteRefresh(code); err != nil { |
|
|
|
|
log.Printf("failed to delete auth code: %v", err) |
|
|
|
|
tokenErr(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
s.logger.Errorf("failed to delete auth code: %v", err) |
|
|
|
|
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
refresh.RefreshToken = storage.NewID() |
|
|
|
|
if err := s.storage.CreateRefresh(refresh); err != nil { |
|
|
|
|
log.Printf("failed to create refresh token: %v", err) |
|
|
|
|
tokenErr(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
s.logger.Errorf("failed to create refresh token: %v", err) |
|
|
|
|
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
s.writeAccessToken(w, idToken, refresh.RefreshToken, expiry) |
|
|
|
|
@ -665,8 +674,8 @@ func (s *Server) writeAccessToken(w http.ResponseWriter, idToken, refreshToken s
|
|
|
|
|
} |
|
|
|
|
data, err := json.Marshal(resp) |
|
|
|
|
if err != nil { |
|
|
|
|
log.Printf("failed to marshal access token response: %v", err) |
|
|
|
|
tokenErr(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
s.logger.Errorf("failed to marshal access token response: %v", err) |
|
|
|
|
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
w.Header().Set("Content-Type", "application/json") |
|
|
|
|
@ -681,3 +690,9 @@ func (s *Server) renderError(w http.ResponseWriter, status int, err, description
|
|
|
|
|
func (s *Server) notFound(w http.ResponseWriter, r *http.Request) { |
|
|
|
|
http.NotFound(w, r) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (s *Server) tokenErrHelper(w http.ResponseWriter, typ string, description string, statusCode int) { |
|
|
|
|
if err := tokenErr(w, typ, description, statusCode); err != nil { |
|
|
|
|
s.logger.Errorf("token error repsonse: %v", err) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|