mirror of
https://github.com/pomerium/pomerium.git
synced 2025-05-29 17:07:24 +02:00
authorize: move sign out and jwks urls to route, update issuer for JWT (#4046)
* authorize: move sign out and jwks urls to route, update issuer for JWT * fix test
This commit is contained in:
parent
376bfe053d
commit
1dee325b72
10 changed files with 36 additions and 34 deletions
|
@ -17,7 +17,6 @@ import (
|
|||
"github.com/pomerium/pomerium/internal/httputil"
|
||||
"github.com/pomerium/pomerium/internal/log"
|
||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||
"github.com/pomerium/pomerium/internal/urlutil"
|
||||
"github.com/pomerium/pomerium/pkg/contextutil"
|
||||
"github.com/pomerium/pomerium/pkg/cryptutil"
|
||||
"github.com/pomerium/pomerium/pkg/policy/criteria"
|
||||
|
@ -204,12 +203,6 @@ func (e *Evaluator) updateStore(cfg *evaluatorConfig) error {
|
|||
return fmt.Errorf("authorize: couldn't create signer: %w", err)
|
||||
}
|
||||
|
||||
authenticateURL, err := urlutil.ParseAndValidateURL(cfg.authenticateURL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("authorize: invalid authenticate URL: %w", err)
|
||||
}
|
||||
|
||||
e.store.UpdateIssuer(authenticateURL.Host)
|
||||
e.store.UpdateGoogleCloudServerlessAuthenticationServiceAccount(
|
||||
cfg.googleCloudServerlessAuthenticationServiceAccount,
|
||||
)
|
||||
|
|
|
@ -33,7 +33,6 @@ func TestEvaluator(t *testing.T) {
|
|||
ctx := context.Background()
|
||||
ctx = storage.WithQuerier(ctx, storage.NewStaticQuerier(data...))
|
||||
store := store.New()
|
||||
store.UpdateIssuer("authenticate.example.com")
|
||||
store.UpdateJWTClaimHeaders(config.NewJWTClaimHeaders("email", "groups", "user", "CUSTOM_KEY"))
|
||||
store.UpdateSigningKey(privateJWK)
|
||||
e, err := New(ctx, store, options...)
|
||||
|
|
|
@ -20,7 +20,7 @@ import (
|
|||
type HeadersRequest struct {
|
||||
EnableGoogleCloudServerlessAuthentication bool `json:"enable_google_cloud_serverless_authentication"`
|
||||
EnableRoutingKey bool `json:"enable_routing_key"`
|
||||
FromAudience string `json:"from_audience"`
|
||||
Issuer string `json:"issuer"`
|
||||
KubernetesServiceAccountToken string `json:"kubernetes_service_account_token"`
|
||||
ToAudience string `json:"to_audience"`
|
||||
Session RequestSession `json:"session"`
|
||||
|
@ -35,7 +35,7 @@ func NewHeadersRequestFromPolicy(policy *config.Policy) *HeadersRequest {
|
|||
input.EnableRoutingKey = policy.EnvoyOpts.GetLbPolicy() == envoy_config_cluster_v3.Cluster_RING_HASH ||
|
||||
policy.EnvoyOpts.GetLbPolicy() == envoy_config_cluster_v3.Cluster_MAGLEV
|
||||
if u, err := urlutil.ParseAndValidateURL(policy.From); err == nil {
|
||||
input.FromAudience = u.Hostname()
|
||||
input.Issuer = u.Hostname()
|
||||
}
|
||||
input.KubernetesServiceAccountToken = policy.KubernetesServiceAccountToken
|
||||
for _, wu := range policy.To {
|
||||
|
|
|
@ -31,8 +31,8 @@ func TestNewHeadersRequestFromPolicy(t *testing.T) {
|
|||
})
|
||||
assert.Equal(t, &HeadersRequest{
|
||||
EnableGoogleCloudServerlessAuthentication: true,
|
||||
FromAudience: "from.example.com",
|
||||
ToAudience: "https://to.example.com",
|
||||
Issuer: "from.example.com",
|
||||
ToAudience: "https://to.example.com",
|
||||
}, req)
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,6 @@ func TestHeadersEvaluator(t *testing.T) {
|
|||
ctx := context.Background()
|
||||
ctx = storage.WithQuerier(ctx, storage.NewStaticQuerier(data...))
|
||||
store := store.New()
|
||||
store.UpdateIssuer("authenticate.example.com")
|
||||
store.UpdateJWTClaimHeaders(config.NewJWTClaimHeaders("email", "groups", "user", "CUSTOM_KEY"))
|
||||
store.UpdateSigningKey(privateJWK)
|
||||
e, err := NewHeadersEvaluator(ctx, store)
|
||||
|
@ -72,8 +71,8 @@ func TestHeadersEvaluator(t *testing.T) {
|
|||
}},
|
||||
},
|
||||
&HeadersRequest{
|
||||
FromAudience: "from.example.com",
|
||||
ToAudience: "to.example.com",
|
||||
Issuer: "from.example.com",
|
||||
ToAudience: "to.example.com",
|
||||
Session: RequestSession{
|
||||
ID: "s1",
|
||||
},
|
||||
|
@ -87,6 +86,8 @@ func TestHeadersEvaluator(t *testing.T) {
|
|||
err = rawJWT.Claims(publicJWK, &claims)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, claims["iss"], "from.example.com")
|
||||
assert.Equal(t, claims["aud"], "from.example.com")
|
||||
assert.Equal(t, claims["exp"], math.Round(claims["exp"].(float64)))
|
||||
assert.LessOrEqual(t, claims["exp"], float64(time.Now().Add(time.Minute*6).Unix()),
|
||||
"JWT should expire within 5 minutes, but got: %v", claims["exp"])
|
||||
|
@ -104,7 +105,7 @@ func TestHeadersEvaluator(t *testing.T) {
|
|||
}},
|
||||
},
|
||||
&HeadersRequest{
|
||||
FromAudience: "from.example.com",
|
||||
Issuer: "from.example.com",
|
||||
ToAudience: "to.example.com",
|
||||
Session: RequestSession{ID: "s1"},
|
||||
PassAccessToken: true,
|
||||
|
@ -122,10 +123,10 @@ func TestHeadersEvaluator(t *testing.T) {
|
|||
}},
|
||||
},
|
||||
&HeadersRequest{
|
||||
FromAudience: "from.example.com",
|
||||
ToAudience: "to.example.com",
|
||||
Session: RequestSession{ID: "s1"},
|
||||
PassIDToken: true,
|
||||
Issuer: "from.example.com",
|
||||
ToAudience: "to.example.com",
|
||||
Session: RequestSession{ID: "s1"},
|
||||
PassIDToken: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ package pomerium.headers
|
|||
# input:
|
||||
# enable_google_cloud_serverless_authentication: boolean
|
||||
# enable_routing_key: boolean
|
||||
# from_audience: string
|
||||
# issuer: string
|
||||
# kubernetes_service_account_token: string
|
||||
# session:
|
||||
# id: string
|
||||
|
@ -12,7 +12,6 @@ package pomerium.headers
|
|||
# pass_id_token: boolean
|
||||
#
|
||||
# data:
|
||||
# issuer: string
|
||||
# jwt_claim_headers: map[string]string
|
||||
# signing_key:
|
||||
# alg: string
|
||||
|
@ -81,12 +80,16 @@ jwt_headers = {
|
|||
}
|
||||
|
||||
jwt_payload_aud = v {
|
||||
v := input.from_audience
|
||||
v := input.issuer
|
||||
} else = "" {
|
||||
true
|
||||
}
|
||||
|
||||
jwt_payload_iss = data.issuer
|
||||
jwt_payload_iss = v {
|
||||
v := input.issuer
|
||||
} else = "" {
|
||||
true
|
||||
}
|
||||
|
||||
jwt_payload_jti = v {
|
||||
v = session.id
|
||||
|
|
|
@ -35,7 +35,6 @@ func TestPolicyEvaluator(t *testing.T) {
|
|||
ctx := context.Background()
|
||||
ctx = storage.WithQuerier(ctx, storage.NewStaticQuerier(data...))
|
||||
store := store.New()
|
||||
store.UpdateIssuer("authenticate.example.com")
|
||||
store.UpdateJWTClaimHeaders(config.NewJWTClaimHeaders("email", "groups", "user", "CUSTOM_KEY"))
|
||||
store.UpdateSigningKey(privateJWK)
|
||||
e, err := NewPolicyEvaluator(ctx, store, policy)
|
||||
|
|
|
@ -36,11 +36,6 @@ func New() *Store {
|
|||
}
|
||||
}
|
||||
|
||||
// UpdateIssuer updates the issuer in the store. The issuer is used as part of JWT construction.
|
||||
func (s *Store) UpdateIssuer(issuer string) {
|
||||
s.write("/issuer", issuer)
|
||||
}
|
||||
|
||||
// UpdateGoogleCloudServerlessAuthenticationServiceAccount updates the google cloud serverless authentication
|
||||
// service account in the store.
|
||||
func (s *Store) UpdateGoogleCloudServerlessAuthenticationServiceAccount(serviceAccount string) {
|
||||
|
|
|
@ -53,8 +53,8 @@ func TestServerHTTP(t *testing.T) {
|
|||
|
||||
expect := map[string]any{
|
||||
"authentication_callback_endpoint": "https://authenticate.localhost.pomerium.io/oauth2/callback",
|
||||
"frontchannel_logout_uri": "https://authenticate.localhost.pomerium.io/.pomerium/sign_out",
|
||||
"jwks_uri": "https://authenticate.localhost.pomerium.io/.well-known/pomerium/jwks.json",
|
||||
"frontchannel_logout_uri": fmt.Sprintf("https://localhost:%s/.pomerium/sign_out", src.GetConfig().HTTPPort),
|
||||
"jwks_uri": fmt.Sprintf("https://localhost:%s/.well-known/pomerium/jwks.json", src.GetConfig().HTTPPort),
|
||||
}
|
||||
assert.Equal(t, expect, actual)
|
||||
})
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/pomerium/csrf"
|
||||
"github.com/pomerium/pomerium/internal/httputil"
|
||||
"github.com/pomerium/pomerium/internal/urlutil"
|
||||
)
|
||||
|
||||
// WellKnownPomerium returns the /.well-known/pomerium handler.
|
||||
|
@ -19,8 +20,8 @@ func WellKnownPomerium(authenticateURL *url.URL) http.Handler {
|
|||
FrontchannelLogoutURI string `json:"frontchannel_logout_uri"` // https://openid.net/specs/openid-connect-frontchannel-1_0.html
|
||||
}{
|
||||
authenticateURL.ResolveReference(&url.URL{Path: "/oauth2/callback"}).String(),
|
||||
authenticateURL.ResolveReference(&url.URL{Path: "/.well-known/pomerium/jwks.json"}).String(),
|
||||
authenticateURL.ResolveReference(&url.URL{Path: "/.pomerium/sign_out"}).String(),
|
||||
urlutil.GetAbsoluteURL(r).ResolveReference(&url.URL{Path: "/.well-known/pomerium/jwks.json"}).String(),
|
||||
urlutil.GetAbsoluteURL(r).ResolveReference(&url.URL{Path: "/.pomerium/sign_out"}).String(),
|
||||
}
|
||||
w.Header().Set("X-CSRF-Token", csrf.Token(r))
|
||||
httputil.RenderJSON(w, http.StatusOK, wellKnownURLs)
|
||||
|
|
|
@ -21,4 +21,15 @@ func TestWellKnownPomeriumHandler(t *testing.T) {
|
|||
WellKnownPomerium(authenticateURL).ServeHTTP(w, r)
|
||||
assert.Equal(t, http.StatusNoContent, w.Result().StatusCode)
|
||||
})
|
||||
t.Run("links", func(t *testing.T) {
|
||||
authenticateURL, _ := url.Parse("https://authenticate.example.com")
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest(http.MethodGet, "https://route.example.com", nil)
|
||||
WellKnownPomerium(authenticateURL).ServeHTTP(w, r)
|
||||
assert.JSONEq(t, `{
|
||||
"authentication_callback_endpoint": "https://authenticate.example.com/oauth2/callback",
|
||||
"frontchannel_logout_uri": "https://route.example.com/.pomerium/sign_out",
|
||||
"jwks_uri": "https://route.example.com/.well-known/pomerium/jwks.json"
|
||||
}`, w.Body.String())
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue