identity: add support for verifying access and identity tokens

This commit is contained in:
Caleb Doxsey 2025-02-13 15:18:23 -07:00
parent 3043e98fab
commit 4d04838ebd
18 changed files with 1126 additions and 609 deletions

View file

@ -3,11 +3,12 @@ package authenticate
import ( import (
"context" "context"
oteltrace "go.opentelemetry.io/otel/trace"
"github.com/pomerium/pomerium/config" "github.com/pomerium/pomerium/config"
"github.com/pomerium/pomerium/internal/urlutil" "github.com/pomerium/pomerium/internal/urlutil"
"github.com/pomerium/pomerium/pkg/identity" "github.com/pomerium/pomerium/pkg/identity"
"github.com/pomerium/pomerium/pkg/identity/oauth" "github.com/pomerium/pomerium/pkg/identity/oauth"
oteltrace "go.opentelemetry.io/otel/trace"
) )
func defaultGetIdentityProvider(ctx context.Context, tracerProvider oteltrace.TracerProvider, options *config.Options, idpID string) (identity.Authenticator, error) { func defaultGetIdentityProvider(ctx context.Context, tracerProvider oteltrace.TracerProvider, options *config.Options, idpID string) (identity.Authenticator, error) {
@ -26,7 +27,8 @@ func defaultGetIdentityProvider(ctx context.Context, tracerProvider oteltrace.Tr
if err != nil { if err != nil {
return nil, err return nil, err
} }
return identity.NewAuthenticator(ctx, tracerProvider, oauth.Options{
o := oauth.Options{
RedirectURL: redirectURL, RedirectURL: redirectURL,
ProviderName: idp.GetType(), ProviderName: idp.GetType(),
ProviderURL: idp.GetUrl(), ProviderURL: idp.GetUrl(),
@ -34,5 +36,9 @@ func defaultGetIdentityProvider(ctx context.Context, tracerProvider oteltrace.Tr
ClientSecret: idp.GetClientSecret(), ClientSecret: idp.GetClientSecret(),
Scopes: idp.GetScopes(), Scopes: idp.GetScopes(),
AuthCodeOptions: idp.GetRequestParams(), AuthCodeOptions: idp.GetRequestParams(),
}) }
if v := idp.GetAccessTokenAllowedAudiences(); v != nil {
o.AccessTokenAllowedAudiences = &v.Values
}
return identity.NewAuthenticator(ctx, tracerProvider, o)
} }

View file

@ -1,6 +1,8 @@
package config package config
import ( import (
"slices"
"github.com/pomerium/pomerium/internal/urlutil" "github.com/pomerium/pomerium/internal/urlutil"
"github.com/pomerium/pomerium/pkg/grpc/identity" "github.com/pomerium/pomerium/pkg/grpc/identity"
) )
@ -43,6 +45,11 @@ func (o *Options) GetIdentityProviderForPolicy(policy *Policy) (*identity.Provid
Url: o.ProviderURL, Url: o.ProviderURL,
RequestParams: o.RequestParams, RequestParams: o.RequestParams,
} }
if v := o.IDPAccessTokenAllowedAudiences; v != nil {
idp.AccessTokenAllowedAudiences = &identity.Provider_StringList{
Values: slices.Clone(*v),
}
}
if policy != nil { if policy != nil {
if policy.IDPClientID != "" { if policy.IDPClientID != "" {
idp.ClientId = policy.IDPClientID idp.ClientId = policy.IDPClientID

View file

@ -15,6 +15,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"reflect" "reflect"
"slices"
"strings" "strings"
"time" "time"
@ -152,12 +153,13 @@ type Options struct {
// Identity provider configuration variables as specified by RFC6749 // Identity provider configuration variables as specified by RFC6749
// https://openid.net/specs/openid-connect-basic-1_0.html#RFC6749 // https://openid.net/specs/openid-connect-basic-1_0.html#RFC6749
ClientID string `mapstructure:"idp_client_id" yaml:"idp_client_id,omitempty"` ClientID string `mapstructure:"idp_client_id" yaml:"idp_client_id,omitempty"`
ClientSecret string `mapstructure:"idp_client_secret" yaml:"idp_client_secret,omitempty"` ClientSecret string `mapstructure:"idp_client_secret" yaml:"idp_client_secret,omitempty"`
ClientSecretFile string `mapstructure:"idp_client_secret_file" yaml:"idp_client_secret_file,omitempty"` ClientSecretFile string `mapstructure:"idp_client_secret_file" yaml:"idp_client_secret_file,omitempty"`
Provider string `mapstructure:"idp_provider" yaml:"idp_provider,omitempty"` Provider string `mapstructure:"idp_provider" yaml:"idp_provider,omitempty"`
ProviderURL string `mapstructure:"idp_provider_url" yaml:"idp_provider_url,omitempty"` ProviderURL string `mapstructure:"idp_provider_url" yaml:"idp_provider_url,omitempty"`
Scopes []string `mapstructure:"idp_scopes" yaml:"idp_scopes,omitempty"` Scopes []string `mapstructure:"idp_scopes" yaml:"idp_scopes,omitempty"`
IDPAccessTokenAllowedAudiences *[]string `mapstructure:"idp_access_token_allowed_audiences" yaml:"idp_access_token_allowed_audiences,omitempty"`
// RequestParams are custom request params added to the signin request as // RequestParams are custom request params added to the signin request as
// part of an Oauth2 code flow. // part of an Oauth2 code flow.
@ -1487,6 +1489,12 @@ func (o *Options) ApplySettings(ctx context.Context, certsIndex *cryptutil.Certi
set(&o.ProviderURL, settings.IdpProviderUrl) set(&o.ProviderURL, settings.IdpProviderUrl)
setSlice(&o.Scopes, settings.Scopes) setSlice(&o.Scopes, settings.Scopes)
setMap(&o.RequestParams, settings.RequestParams) setMap(&o.RequestParams, settings.RequestParams)
if settings.IdpAccessTokenAllowedAudiences != nil {
values := slices.Clone(settings.IdpAccessTokenAllowedAudiences.Values)
o.IDPAccessTokenAllowedAudiences = &values
} else {
o.IDPAccessTokenAllowedAudiences = nil
}
setSlice(&o.AuthorizeURLStrings, settings.AuthorizeServiceUrls) setSlice(&o.AuthorizeURLStrings, settings.AuthorizeServiceUrls)
set(&o.AuthorizeInternalURLString, settings.AuthorizeInternalServiceUrl) set(&o.AuthorizeInternalURLString, settings.AuthorizeInternalServiceUrl)
set(&o.OverrideCertificateName, settings.OverrideCertificateName) set(&o.OverrideCertificateName, settings.OverrideCertificateName)
@ -1591,6 +1599,13 @@ func (o *Options) ToProto() *config.Config {
copySrcToOptionalDest(&settings.IdpProviderUrl, &o.ProviderURL) copySrcToOptionalDest(&settings.IdpProviderUrl, &o.ProviderURL)
settings.Scopes = o.Scopes settings.Scopes = o.Scopes
settings.RequestParams = o.RequestParams settings.RequestParams = o.RequestParams
if o.IDPAccessTokenAllowedAudiences != nil {
settings.IdpAccessTokenAllowedAudiences = &config.Settings_StringList{
Values: slices.Clone(*o.IDPAccessTokenAllowedAudiences),
}
} else {
settings.IdpAccessTokenAllowedAudiences = nil
}
settings.AuthorizeServiceUrls = o.AuthorizeURLStrings settings.AuthorizeServiceUrls = o.AuthorizeURLStrings
copySrcToOptionalDest(&settings.AuthorizeInternalServiceUrl, &o.AuthorizeInternalURLString) copySrcToOptionalDest(&settings.AuthorizeInternalServiceUrl, &o.AuthorizeInternalURLString)
copySrcToOptionalDest(&settings.OverrideCertificateName, &o.OverrideCertificateName) copySrcToOptionalDest(&settings.OverrideCertificateName, &o.OverrideCertificateName)

View file

@ -8,6 +8,7 @@ import (
"net/url" "net/url"
"os" "os"
"regexp" "regexp"
"slices"
"sort" "sort"
"strings" "strings"
"time" "time"
@ -186,6 +187,8 @@ type Policy struct {
IDPClientID string `mapstructure:"idp_client_id" yaml:"idp_client_id,omitempty"` IDPClientID string `mapstructure:"idp_client_id" yaml:"idp_client_id,omitempty"`
// IDPClientSecret is the client secret used for the identity provider. // IDPClientSecret is the client secret used for the identity provider.
IDPClientSecret string `mapstructure:"idp_client_secret" yaml:"idp_client_secret,omitempty"` IDPClientSecret string `mapstructure:"idp_client_secret" yaml:"idp_client_secret,omitempty"`
// IDPAccessTokenAllowedAudiences are the allowed audiences for idp access token validation.
IDPAccessTokenAllowedAudiences *[]string `mapstructure:"idp_access_token_allowed_audiences" yaml:"idp_access_token_allowed_audiences,omitempty"`
// ShowErrorDetails indicates whether or not additional error details should be displayed. // ShowErrorDetails indicates whether or not additional error details should be displayed.
ShowErrorDetails bool `mapstructure:"show_error_details" yaml:"show_error_details" json:"show_error_details"` ShowErrorDetails bool `mapstructure:"show_error_details" yaml:"show_error_details" json:"show_error_details"`
@ -332,6 +335,12 @@ func NewPolicyFromProto(pb *configpb.Route) (*Policy, error) {
TLSUpstreamServerName: pb.GetTlsUpstreamServerName(), TLSUpstreamServerName: pb.GetTlsUpstreamServerName(),
UpstreamTimeout: timeout, UpstreamTimeout: timeout,
} }
if pb.IdpAccessTokenAllowedAudiences != nil {
values := slices.Clone(pb.IdpAccessTokenAllowedAudiences.Values)
p.IDPAccessTokenAllowedAudiences = &values
} else {
p.IDPAccessTokenAllowedAudiences = nil
}
if pb.Redirect.IsSet() { if pb.Redirect.IsSet() {
p.Redirect = &PolicyRedirect{ p.Redirect = &PolicyRedirect{
HTTPSRedirect: pb.Redirect.HttpsRedirect, HTTPSRedirect: pb.Redirect.HttpsRedirect,
@ -505,6 +514,13 @@ func (p *Policy) ToProto() (*configpb.Route, error) {
if p.IDPClientSecret != "" { if p.IDPClientSecret != "" {
pb.IdpClientSecret = proto.String(p.IDPClientSecret) pb.IdpClientSecret = proto.String(p.IDPClientSecret)
} }
if p.IDPAccessTokenAllowedAudiences != nil {
pb.IdpAccessTokenAllowedAudiences = &configpb.Route_StringList{
Values: slices.Clone(*p.IDPAccessTokenAllowedAudiences),
}
} else {
pb.IdpAccessTokenAllowedAudiences = nil
}
if p.Redirect != nil { if p.Redirect != nil {
pb.Redirect = &configpb.RouteRedirect{ pb.Redirect = &configpb.RouteRedirect{
HttpsRedirect: p.Redirect.HTTPSRedirect, HttpsRedirect: p.Redirect.HTTPSRedirect,

File diff suppressed because it is too large Load diff

View file

@ -45,8 +45,10 @@ enum IssuerFormat {
IssuerURI = 1; IssuerURI = 1;
} }
// Next ID: 69. // Next ID: 70.
message Route { message Route {
message StringList { repeated string values = 1; }
string name = 1; string name = 1;
string description = 67; string description = 67;
string logo_url = 68; string logo_url = 68;
@ -130,6 +132,7 @@ message Route {
optional string idp_client_id = 55; optional string idp_client_id = 55;
optional string idp_client_secret = 56; optional string idp_client_secret = 56;
optional StringList idp_access_token_allowed_audiences = 69;
bool show_error_details = 59; bool show_error_details = 59;
} }
@ -149,7 +152,7 @@ message Policy {
string remediation = 9; string remediation = 9;
} }
// Next ID: 137. // Next ID: 138.
message Settings { message Settings {
message Certificate { message Certificate {
bytes cert_bytes = 3; bytes cert_bytes = 3;
@ -188,6 +191,7 @@ message Settings {
optional string idp_client_secret = 23; optional string idp_client_secret = 23;
optional string idp_provider = 24; optional string idp_provider = 24;
optional string idp_provider_url = 25; optional string idp_provider_url = 25;
optional StringList idp_access_token_allowed_audiences = 137;
repeated string scopes = 26; repeated string scopes = 26;
// optional string idp_service_account = 27; // optional string idp_service_account = 27;
// optional google.protobuf.Duration idp_refresh_directory_timeout = 28; // optional google.protobuf.Duration idp_refresh_directory_timeout = 28;

View file

@ -33,8 +33,9 @@ type Provider struct {
Type string `protobuf:"bytes,4,opt,name=type,proto3" json:"type,omitempty"` Type string `protobuf:"bytes,4,opt,name=type,proto3" json:"type,omitempty"`
Scopes []string `protobuf:"bytes,5,rep,name=scopes,proto3" json:"scopes,omitempty"` Scopes []string `protobuf:"bytes,5,rep,name=scopes,proto3" json:"scopes,omitempty"`
// string service_account = 6; // string service_account = 6;
Url string `protobuf:"bytes,7,opt,name=url,proto3" json:"url,omitempty"` Url string `protobuf:"bytes,7,opt,name=url,proto3" json:"url,omitempty"`
RequestParams map[string]string `protobuf:"bytes,8,rep,name=request_params,json=requestParams,proto3" json:"request_params,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` RequestParams map[string]string `protobuf:"bytes,8,rep,name=request_params,json=requestParams,proto3" json:"request_params,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
AccessTokenAllowedAudiences *Provider_StringList `protobuf:"bytes,10,opt,name=access_token_allowed_audiences,json=accessTokenAllowedAudiences,proto3,oneof" json:"access_token_allowed_audiences,omitempty"`
} }
func (x *Provider) Reset() { func (x *Provider) Reset() {
@ -125,6 +126,13 @@ func (x *Provider) GetRequestParams() map[string]string {
return nil return nil
} }
func (x *Provider) GetAccessTokenAllowedAudiences() *Provider_StringList {
if x != nil {
return x.AccessTokenAllowedAudiences
}
return nil
}
type Profile struct { type Profile struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@ -196,6 +204,53 @@ func (x *Profile) GetClaims() *structpb.Struct {
return nil return nil
} }
type Provider_StringList struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Values []string `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"`
}
func (x *Provider_StringList) Reset() {
*x = Provider_StringList{}
if protoimpl.UnsafeEnabled {
mi := &file_identity_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Provider_StringList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Provider_StringList) ProtoMessage() {}
func (x *Provider_StringList) ProtoReflect() protoreflect.Message {
mi := &file_identity_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Provider_StringList.ProtoReflect.Descriptor instead.
func (*Provider_StringList) Descriptor() ([]byte, []int) {
return file_identity_proto_rawDescGZIP(), []int{0, 0}
}
func (x *Provider_StringList) GetValues() []string {
if x != nil {
return x.Values
}
return nil
}
var File_identity_proto protoreflect.FileDescriptor var File_identity_proto protoreflect.FileDescriptor
var file_identity_proto_rawDesc = []byte{ var file_identity_proto_rawDesc = []byte{
@ -203,7 +258,7 @@ var file_identity_proto_rawDesc = []byte{
0x12, 0x11, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x12, 0x11, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74,
0x69, 0x74, 0x79, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x22, 0xed, 0x02, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x0e, 0x6f, 0x22, 0xa8, 0x04, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x0e,
0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x38, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x38,
0x0a, 0x18, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x0a, 0x18, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x73,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09,
@ -221,25 +276,36 @@ var file_identity_proto_rawDesc = []byte{
0x32, 0x2e, 0x2e, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x32, 0x2e, 0x2e, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2e, 0x69, 0x64, 0x65, 0x6e,
0x74, 0x69, 0x74, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2e, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
0x52, 0x0d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x1a, 0x52, 0x0d, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12,
0x40, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x70, 0x0a, 0x1e, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x5f, 0x61, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65,
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x75, 0x6d, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x76,
0x01, 0x22, 0x97, 0x01, 0x0a, 0x07, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x1f, 0x0a, 0x69, 0x64, 0x65, 0x72, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x48,
0x0b, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x00, 0x52, 0x1b, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x41, 0x6c,
0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x49, 0x64, 0x12, 0x19, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x41, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x88, 0x01,
0x0a, 0x08, 0x69, 0x64, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x01, 0x1a, 0x24, 0x0a, 0x0a, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x12,
0x52, 0x07, 0x69, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x61, 0x75, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52,
0x74, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x1a, 0x40, 0x0a, 0x12, 0x52, 0x65, 0x71, 0x75, 0x65,
0x6f, 0x61, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6c, 0x73, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
0x61, 0x69, 0x6d, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
0x75, 0x63, 0x74, 0x52, 0x06, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x73, 0x42, 0x30, 0x5a, 0x2e, 0x67, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x21, 0x0a, 0x1f, 0x5f, 0x61, 0x63,
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77,
0x75, 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x65, 0x64, 0x5f, 0x61, 0x75, 0x64, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x22, 0x97, 0x01, 0x0a,
0x67, 0x72, 0x70, 0x63, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x62, 0x06, 0x70, 0x07, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x76,
0x72, 0x6f, 0x74, 0x6f, 0x33, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70,
0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x64, 0x5f,
0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x69, 0x64, 0x54,
0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x74, 0x6f,
0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x6f, 0x61, 0x75, 0x74, 0x68,
0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2f, 0x0a, 0x06, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x73, 0x18,
0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x06,
0x63, 0x6c, 0x61, 0x69, 0x6d, 0x73, 0x42, 0x30, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x6f, 0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x70, 0x6f,
0x6d, 0x65, 0x72, 0x69, 0x75, 0x6d, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f,
0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (
@ -254,21 +320,23 @@ func file_identity_proto_rawDescGZIP() []byte {
return file_identity_proto_rawDescData return file_identity_proto_rawDescData
} }
var file_identity_proto_msgTypes = make([]protoimpl.MessageInfo, 3) var file_identity_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_identity_proto_goTypes = []any{ var file_identity_proto_goTypes = []any{
(*Provider)(nil), // 0: pomerium.identity.Provider (*Provider)(nil), // 0: pomerium.identity.Provider
(*Profile)(nil), // 1: pomerium.identity.Profile (*Profile)(nil), // 1: pomerium.identity.Profile
nil, // 2: pomerium.identity.Provider.RequestParamsEntry (*Provider_StringList)(nil), // 2: pomerium.identity.Provider.StringList
(*structpb.Struct)(nil), // 3: google.protobuf.Struct nil, // 3: pomerium.identity.Provider.RequestParamsEntry
(*structpb.Struct)(nil), // 4: google.protobuf.Struct
} }
var file_identity_proto_depIdxs = []int32{ var file_identity_proto_depIdxs = []int32{
2, // 0: pomerium.identity.Provider.request_params:type_name -> pomerium.identity.Provider.RequestParamsEntry 3, // 0: pomerium.identity.Provider.request_params:type_name -> pomerium.identity.Provider.RequestParamsEntry
3, // 1: pomerium.identity.Profile.claims:type_name -> google.protobuf.Struct 2, // 1: pomerium.identity.Provider.access_token_allowed_audiences:type_name -> pomerium.identity.Provider.StringList
2, // [2:2] is the sub-list for method output_type 4, // 2: pomerium.identity.Profile.claims:type_name -> google.protobuf.Struct
2, // [2:2] is the sub-list for method input_type 3, // [3:3] is the sub-list for method output_type
2, // [2:2] is the sub-list for extension type_name 3, // [3:3] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension extendee 3, // [3:3] is the sub-list for extension type_name
0, // [0:2] is the sub-list for field type_name 3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
} }
func init() { file_identity_proto_init() } func init() { file_identity_proto_init() }
@ -301,14 +369,27 @@ func file_identity_proto_init() {
return nil return nil
} }
} }
file_identity_proto_msgTypes[2].Exporter = func(v any, i int) any {
switch v := v.(*Provider_StringList); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
} }
file_identity_proto_msgTypes[0].OneofWrappers = []any{}
type x struct{} type x struct{}
out := protoimpl.TypeBuilder{ out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{ File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_identity_proto_rawDesc, RawDescriptor: file_identity_proto_rawDesc,
NumEnums: 0, NumEnums: 0,
NumMessages: 3, NumMessages: 4,
NumExtensions: 0, NumExtensions: 0,
NumServices: 0, NumServices: 0,
}, },

View file

@ -6,6 +6,7 @@ option go_package = "github.com/pomerium/pomerium/pkg/grpc/identity";
import "google/protobuf/struct.proto"; import "google/protobuf/struct.proto";
message Provider { message Provider {
message StringList { repeated string values = 1; }
string id = 1; string id = 1;
string authenticate_service_url = 9; string authenticate_service_url = 9;
string client_id = 2; string client_id = 2;
@ -15,6 +16,7 @@ message Provider {
// string service_account = 6; // string service_account = 6;
string url = 7; string url = 7;
map<string, string> request_params = 8; map<string, string> request_params = 8;
optional StringList access_token_allowed_audiences = 10;
} }
message Profile { message Profile {

9
pkg/identity/errors.go Normal file
View file

@ -0,0 +1,9 @@
package identity
import "github.com/pomerium/pomerium/pkg/identity/identity"
// re-exported errors
var (
ErrVerifyAccessTokenNotSupported = identity.ErrVerifyAccessTokenNotSupported
ErrVerifyIdentityTokenNotSupported = identity.ErrVerifyIdentityTokenNotSupported
)

View file

@ -0,0 +1,9 @@
package identity
import "errors"
// well known errors
var (
ErrVerifyAccessTokenNotSupported = errors.New("identity: access token verification not supported")
ErrVerifyIdentityTokenNotSupported = errors.New("identity: identity token verification not supported")
)

View file

@ -2,6 +2,7 @@ package identity
import ( import (
"context" "context"
"fmt"
"net/http" "net/http"
"golang.org/x/oauth2" "golang.org/x/oauth2"
@ -55,3 +56,13 @@ func (mp MockProvider) SignOut(_ http.ResponseWriter, _ *http.Request, _, _, _ s
func (mp MockProvider) SignIn(_ http.ResponseWriter, _ *http.Request, _ string) error { func (mp MockProvider) SignIn(_ http.ResponseWriter, _ *http.Request, _ string) error {
return mp.SignInError return mp.SignInError
} }
// VerifyAccessToken verifies an access token.
func (mp MockProvider) VerifyAccessToken(_ context.Context, _ string) (claims map[string]any, err error) {
return nil, fmt.Errorf("VerifyAccessToken not implemented")
}
// VerifyIdentityToken verifies an identity token.
func (mp MockProvider) VerifyIdentityToken(_ context.Context, _ string) (claims map[string]any, err error) {
return nil, fmt.Errorf("VerifyIdentityToken not implemented")
}

View file

@ -182,3 +182,13 @@ func (p *Provider) SignIn(w http.ResponseWriter, r *http.Request, state string)
func (p *Provider) SignOut(_ http.ResponseWriter, _ *http.Request, _, _, _ string) error { func (p *Provider) SignOut(_ http.ResponseWriter, _ *http.Request, _, _, _ string) error {
return oidc.ErrSignoutNotImplemented return oidc.ErrSignoutNotImplemented
} }
// VerifyAccessToken verifies an access token.
func (p *Provider) VerifyAccessToken(_ context.Context, _ string) (claims map[string]any, err error) {
return nil, identity.ErrVerifyAccessTokenNotSupported
}
// VerifyIdentityToken verifies an identity token.
func (p *Provider) VerifyIdentityToken(_ context.Context, _ string) (claims map[string]any, err error) {
return nil, identity.ErrVerifyIdentityTokenNotSupported
}

View file

@ -256,3 +256,13 @@ func (p *Provider) SignIn(w http.ResponseWriter, r *http.Request, state string)
func (p *Provider) SignOut(_ http.ResponseWriter, _ *http.Request, _, _, _ string) error { func (p *Provider) SignOut(_ http.ResponseWriter, _ *http.Request, _, _, _ string) error {
return oidc.ErrSignoutNotImplemented return oidc.ErrSignoutNotImplemented
} }
// VerifyAccessToken verifies an access token.
func (p *Provider) VerifyAccessToken(_ context.Context, _ string) (claims map[string]any, err error) {
return nil, identity.ErrVerifyAccessTokenNotSupported
}
// VerifyIdentityToken verifies an identity token.
func (p *Provider) VerifyIdentityToken(_ context.Context, _ string) (claims map[string]any, err error) {
return nil, identity.ErrVerifyIdentityTokenNotSupported
}

View file

@ -3,7 +3,9 @@
// authorization with Bearer JWT. // authorization with Bearer JWT.
package oauth package oauth
import "net/url" import (
"net/url"
)
// Options contains the fields required for an OAuth 2.0 (inc. OIDC) auth flow. // Options contains the fields required for an OAuth 2.0 (inc. OIDC) auth flow.
// //
@ -29,4 +31,7 @@ type Options struct {
// AuthCodeOptions specifies additional key value pairs query params to add // AuthCodeOptions specifies additional key value pairs query params to add
// to the request flow signin url. // to the request flow signin url.
AuthCodeOptions map[string]string AuthCodeOptions map[string]string
// When set validates the audience in access tokens.
AccessTokenAllowedAudiences *[]string
} }

View file

@ -10,8 +10,11 @@ import (
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"slices"
"strings"
go_oidc "github.com/coreos/go-oidc/v3/oidc" go_oidc "github.com/coreos/go-oidc/v3/oidc"
"github.com/google/uuid"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"github.com/pomerium/pomerium/pkg/identity/oauth" "github.com/pomerium/pomerium/pkg/identity/oauth"
@ -37,11 +40,13 @@ var defaultAuthCodeOptions = map[string]string{"prompt": "select_account"}
// Provider is an Azure implementation of the Authenticator interface. // Provider is an Azure implementation of the Authenticator interface.
type Provider struct { type Provider struct {
*pom_oidc.Provider *pom_oidc.Provider
accessTokenAllowedAudiences *[]string
} }
// New instantiates an OpenID Connect (OIDC) provider for Azure. // New instantiates an OpenID Connect (OIDC) provider for Azure.
func New(ctx context.Context, o *oauth.Options) (*Provider, error) { func New(ctx context.Context, o *oauth.Options) (*Provider, error) {
var p Provider var p Provider
p.accessTokenAllowedAudiences = o.AccessTokenAllowedAudiences
var err error var err error
if o.ProviderURL == "" { if o.ProviderURL == "" {
o.ProviderURL = defaultProviderURL o.ProviderURL = defaultProviderURL
@ -73,6 +78,59 @@ func (p *Provider) Name() string {
return Name return Name
} }
// VerifyAccessToken verifies a raw access token.
func (p *Provider) VerifyAccessToken(ctx context.Context, rawAccessToken string) (claims map[string]any, err error) {
pp, err := p.GetProvider()
if err != nil {
return nil, fmt.Errorf("error getting oidc provider: %w", err)
}
// azure access tokens are JWTs signed with the same keys as identity tokens
verifier := pp.Verifier(&go_oidc.Config{
SkipClientIDCheck: true,
SkipIssuerCheck: true, // checked later
})
token, err := verifier.Verify(ctx, rawAccessToken)
if err != nil {
return nil, fmt.Errorf("error verifying access token: %w", err)
}
claims = map[string]any{}
err = token.Claims(&claims)
if err != nil {
return nil, fmt.Errorf("error unmarshaling access token claims: %w", err)
}
// verify audience
if p.accessTokenAllowedAudiences != nil {
if audience, ok := claims["aud"].(string); !ok || !slices.Contains(*p.accessTokenAllowedAudiences, audience) {
return nil, fmt.Errorf("error verifying access token audience claim, invalid audience")
}
}
err = verifyIssuer(pp, claims)
if err != nil {
return nil, fmt.Errorf("error verifying access token issuer claim: %w", err)
}
if scope, ok := claims["scp"].(string); ok && slices.Contains(strings.Fields(scope), "openid") {
userInfo, err := pp.UserInfo(ctx, oauth2.StaticTokenSource(&oauth2.Token{
TokenType: "Bearer",
AccessToken: rawAccessToken,
}))
if err != nil {
return nil, fmt.Errorf("error calling user info endpoint: %w", err)
}
err = userInfo.Claims(claims)
if err != nil {
return nil, fmt.Errorf("error unmarshaling user info claims: %w", err)
}
}
return claims, nil
}
// newProvider overrides the default round tripper for well-known endpoint call that happens // newProvider overrides the default round tripper for well-known endpoint call that happens
// on new provider registration. // on new provider registration.
// By default, the "common" (both public and private domains) responds with // By default, the "common" (both public and private domains) responds with
@ -128,3 +186,55 @@ func (transport *wellKnownConfiguration) RoundTrip(req *http.Request) (*http.Res
res.Body = io.NopCloser(bytes.NewReader(bs)) res.Body = io.NopCloser(bytes.NewReader(bs))
return res, nil return res, nil
} }
const (
v1IssuerPrefix = "https://sts.windows.net/"
v1IssuerSuffix = "/"
v2IssuerPrefix = "https://login.microsoftonline.com/"
v2IssuerSuffix = "/v2.0"
)
func verifyIssuer(pp *go_oidc.Provider, claims map[string]any) error {
tenantID, ok := getTenantIDFromURL(pp.Endpoint().TokenURL)
if !ok {
return fmt.Errorf("failed to find tenant id")
}
iss, ok := claims["iss"].(string)
if !ok {
return fmt.Errorf("missing issuer claim")
}
if !(iss == v1IssuerPrefix+tenantID+v1IssuerSuffix || iss == v2IssuerPrefix+tenantID+v2IssuerSuffix) {
return fmt.Errorf("invalid issuer: %s", iss)
}
return nil
}
func getTenantIDFromURL(rawTokenURL string) (string, bool) {
// URLs look like:
// - https://login.microsoftonline.com/f42bce3b-671c-4162-b24c-00ecc7641897/v2.0
// Or:
// - https://sts.windows.net/f42bce3b-671c-4162-b24c-00ecc7641897/
for _, prefix := range []string{v1IssuerPrefix, v2IssuerPrefix} {
path, ok := strings.CutPrefix(rawTokenURL, prefix)
if !ok {
continue
}
idx := strings.Index(path, "/")
if idx <= 0 {
continue
}
rawTenantID := path[:idx]
if _, err := uuid.Parse(rawTenantID); err != nil {
continue
}
return rawTenantID, true
}
return "", false
}

View file

@ -2,15 +2,27 @@ package azure
import ( import (
"context" "context"
"crypto/rand"
"crypto/rsa"
"encoding/json"
"net/http"
"net/http/httptest"
"testing" "testing"
"time"
"github.com/go-jose/go-jose/v3"
"github.com/go-jose/go-jose/v3/jwt"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/pomerium/pomerium/internal/testutil"
"github.com/pomerium/pomerium/pkg/identity/identity"
"github.com/pomerium/pomerium/pkg/identity/oauth" "github.com/pomerium/pomerium/pkg/identity/oauth"
) )
func TestAuthCodeOptions(t *testing.T) { func TestAuthCodeOptions(t *testing.T) {
t.Parallel()
var options oauth.Options var options oauth.Options
p, err := New(context.Background(), &options) p, err := New(context.Background(), &options)
require.NoError(t, err) require.NoError(t, err)
@ -21,3 +33,101 @@ func TestAuthCodeOptions(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, map[string]string{}, p.AuthCodeOptions) assert.Equal(t, map[string]string{}, p.AuthCodeOptions)
} }
func TestVerifyAccessToken(t *testing.T) {
t.Parallel()
ctx := testutil.GetContext(t, time.Minute)
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
require.NoError(t, err)
jwtSigner, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.RS256, Key: privateKey}, nil)
require.NoError(t, err)
iat := time.Now().Unix()
exp := iat + 3600
rawAccessToken1, err := jwt.Signed(jwtSigner).Claims(map[string]any{
"iss": "https://sts.windows.net/323b4000-7ad7-4ed3-9f4e-adee06ee8bbe/",
"aud": "https://client.example.com",
"sub": "subject",
"exp": exp,
"iat": iat,
}).CompactSerialize()
require.NoError(t, err)
rawAccessToken2, err := jwt.Signed(jwtSigner).Claims(map[string]any{
"iss": "https://sts.windows.net/323b4000-7ad7-4ed3-9f4e-adee06ee8bbe/",
"aud": "https://unexpected.example.com",
"sub": "subject",
"exp": exp,
"iat": iat,
}).CompactSerialize()
require.NoError(t, err)
var srvURL string
mux := http.NewServeMux()
mux.HandleFunc("GET /.well-known/openid-configuration", func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
json.NewEncoder(w).Encode(map[string]any{
"issuer": srvURL,
"authorization_endpoint": srvURL + "/auth",
"token_endpoint": "https://sts.windows.net/323b4000-7ad7-4ed3-9f4e-adee06ee8bbe/token",
"jwks_uri": srvURL + "/keys",
"id_token_signing_alg_values_supported": []any{"RS256"},
})
})
mux.HandleFunc("GET /keys", func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
json.NewEncoder(w).Encode(jose.JSONWebKeySet{
Keys: []jose.JSONWebKey{
{Key: privateKey.Public(), Use: "sig", Algorithm: "RS256"},
},
})
})
srv := httptest.NewServer(mux)
srvURL = srv.URL
audiences := []string{"https://other.example.com", "https://client.example.com"}
p, err := New(ctx, &oauth.Options{
ProviderName: Name,
ProviderURL: srv.URL,
ClientID: "CLIENT_ID",
ClientSecret: "CLIENT_SECRET",
AccessTokenAllowedAudiences: &audiences,
})
require.NoError(t, err)
claims, err := p.VerifyAccessToken(ctx, rawAccessToken1)
require.NoError(t, err)
delete(claims, "iat")
delete(claims, "exp")
assert.Equal(t, map[string]any{
"iss": "https://sts.windows.net/323b4000-7ad7-4ed3-9f4e-adee06ee8bbe/",
"aud": "https://client.example.com",
"sub": "subject",
}, claims)
_, err = p.VerifyAccessToken(ctx, rawAccessToken2)
assert.ErrorContains(t, err, "invalid audience")
}
func TestVerifyIdentityToken(t *testing.T) {
t.Parallel()
ctx := testutil.GetContext(t, time.Minute)
mux := http.NewServeMux()
srv := httptest.NewServer(mux)
p, err := New(ctx, &oauth.Options{
ProviderName: Name,
ProviderURL: srv.URL,
ClientID: "CLIENT_ID",
ClientSecret: "CLIENT_SECRET",
})
require.NoError(t, err)
claims, err := p.VerifyIdentityToken(ctx, "RAW IDENTITY TOKEN")
assert.ErrorIs(t, identity.ErrVerifyIdentityTokenNotSupported, err)
assert.Nil(t, claims)
}

View file

@ -360,3 +360,13 @@ func (p *Provider) SignOut(w http.ResponseWriter, r *http.Request, idTokenHint,
httputil.Redirect(w, r, endSessionURL.String(), http.StatusFound) httputil.Redirect(w, r, endSessionURL.String(), http.StatusFound)
return nil return nil
} }
// VerifyAccessToken verifies an access token.
func (p *Provider) VerifyAccessToken(_ context.Context, _ string) (claims map[string]any, err error) {
return nil, identity.ErrVerifyAccessTokenNotSupported
}
// VerifyIdentityToken verifies an identity token.
func (p *Provider) VerifyIdentityToken(_ context.Context, _ string) (claims map[string]any, err error) {
return nil, identity.ErrVerifyIdentityTokenNotSupported
}

View file

@ -8,6 +8,7 @@ import (
"net/http" "net/http"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
oteltrace "go.opentelemetry.io/otel/trace"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"github.com/pomerium/pomerium/pkg/identity/identity" "github.com/pomerium/pomerium/pkg/identity/identity"
@ -23,7 +24,6 @@ import (
"github.com/pomerium/pomerium/pkg/identity/oidc/okta" "github.com/pomerium/pomerium/pkg/identity/oidc/okta"
"github.com/pomerium/pomerium/pkg/identity/oidc/onelogin" "github.com/pomerium/pomerium/pkg/identity/oidc/onelogin"
"github.com/pomerium/pomerium/pkg/identity/oidc/ping" "github.com/pomerium/pomerium/pkg/identity/oidc/ping"
oteltrace "go.opentelemetry.io/otel/trace"
) )
// State is the identity state. // State is the identity state.
@ -36,6 +36,8 @@ type Authenticator interface {
Revoke(context.Context, *oauth2.Token) error Revoke(context.Context, *oauth2.Token) error
Name() string Name() string
UpdateUserInfo(ctx context.Context, t *oauth2.Token, v any) error UpdateUserInfo(ctx context.Context, t *oauth2.Token, v any) error
VerifyAccessToken(ctx context.Context, rawAccessToken string) (claims map[string]any, err error)
VerifyIdentityToken(ctx context.Context, rawIdentityToken string) (claims map[string]any, err error)
SignIn(w http.ResponseWriter, r *http.Request, state string) error SignIn(w http.ResponseWriter, r *http.Request, state string) error
SignOut(w http.ResponseWriter, r *http.Request, idTokenHint, authenticateSignedOutURL, redirectToURL string) error SignOut(w http.ResponseWriter, r *http.Request, idTokenHint, authenticateSignedOutURL, redirectToURL string) error