Implement KeyCape provider and service identity contracts
All checks were successful
Build and Publish Container Image / build-and-push (push) Successful in 25s
All checks were successful
Build and Publish Container Image / build-and-push (push) Successful in 25s
Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a02e3f-7301-7622-9be1-12e5f352881c
This commit is contained in:
parent
cdfb046b80
commit
efce3e9331
15 changed files with 579 additions and 26 deletions
|
|
@ -232,11 +232,15 @@ func (h *TokenHandler) serveClientCredentials(w http.ResponseWriter, r *http.Req
|
|||
}
|
||||
|
||||
now := time.Now()
|
||||
tokenLifetime := h.TokenLifetime
|
||||
if client.TokenLifetime > 0 {
|
||||
tokenLifetime = client.TokenLifetime
|
||||
}
|
||||
claims := map[string]interface{}{
|
||||
"iss": h.Issuer,
|
||||
"sub": client.ServiceSubject,
|
||||
"aud": clientID,
|
||||
"exp": now.Add(h.TokenLifetime).Unix(),
|
||||
"exp": now.Add(tokenLifetime).Unix(),
|
||||
"iat": now.Unix(),
|
||||
"tenant": client.Tenant,
|
||||
"principal_type": "service",
|
||||
|
|
@ -265,7 +269,7 @@ func (h *TokenHandler) serveClientCredentials(w http.ResponseWriter, r *http.Req
|
|||
w.WriteHeader(http.StatusOK)
|
||||
_ = json.NewEncoder(w).Encode(tokenResponse{
|
||||
AccessToken: jwtToken, TokenType: "Bearer",
|
||||
ExpiresIn: int(h.TokenLifetime.Seconds()),
|
||||
ExpiresIn: int(tokenLifetime.Seconds()),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -291,6 +291,30 @@ func TestTokenHandler_ClientCredentials_ReturnsScopedServiceToken(t *testing.T)
|
|||
}
|
||||
}
|
||||
|
||||
func TestTokenHandler_ClientCredentials_UsesPerClientLifetime(t *testing.T) {
|
||||
h := serviceTokenHandler(t)
|
||||
h.ClientConfig["rapp-qonto"].TokenLifetime = 5 * time.Minute
|
||||
req := tokenRequest(url.Values{
|
||||
"grant_type": {"client_credentials"},
|
||||
"scope": {"finance.qonto.read"},
|
||||
})
|
||||
req.SetBasicAuth("rapp-qonto", "test-service-secret")
|
||||
w := httptest.NewRecorder()
|
||||
h.ServeHTTP(w, req)
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d: %s", w.Code, w.Body.String())
|
||||
}
|
||||
resp := decodeTokenResponse(t, w.Body.String())
|
||||
if got := int(resp["expires_in"].(float64)); got != 300 {
|
||||
t.Fatalf("expires_in: want 300, got %d", got)
|
||||
}
|
||||
claims := parseJWTPayload(t, resp["access_token"].(string))
|
||||
ttl := int64(claims["exp"].(float64) - claims["iat"].(float64))
|
||||
if ttl != 300 {
|
||||
t.Fatalf("JWT lifetime: want 300 seconds, got %d", ttl)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTokenHandler_ClientCredentials_RejectsWrongSecret(t *testing.T) {
|
||||
h := serviceTokenHandler(t)
|
||||
req := tokenRequest(url.Values{"grant_type": {"client_credentials"}})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue