2020-05-26 19:56:10 +01:00
package options
import (
"fmt"
"net/url"
2023-09-08 17:27:15 +02:00
"reflect"
2020-05-26 19:56:10 +01:00
"strconv"
2020-08-31 14:05:52 +01:00
"strings"
2020-05-26 19:56:10 +01:00
"time"
2020-09-30 01:44:42 +09:00
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
2020-07-12 16:47:25 +01:00
"github.com/spf13/pflag"
2020-05-26 19:56:10 +01:00
)
type LegacyOptions struct {
// Legacy options related to upstream servers
2020-07-12 16:47:25 +01:00
LegacyUpstreams LegacyUpstreams ` cfg:",squash" `
2020-05-26 19:56:10 +01:00
2020-07-29 20:08:46 +01:00
// Legacy options for injecting request/response headers
LegacyHeaders LegacyHeaders ` cfg:",squash" `
2021-02-14 18:47:15 +00:00
// Legacy options for the server address and TLS
LegacyServer LegacyServer ` cfg:",squash" `
2021-04-03 19:06:30 +03:00
// Legacy options for single provider
LegacyProvider LegacyProvider ` cfg:",squash" `
2020-05-26 19:56:10 +01:00
Options Options ` cfg:",squash" `
}
func NewLegacyOptions ( ) * LegacyOptions {
return & LegacyOptions {
2020-07-12 16:47:25 +01:00
LegacyUpstreams : LegacyUpstreams {
PassHostHeader : true ,
ProxyWebSockets : true ,
2020-11-19 10:35:04 +00:00
FlushInterval : DefaultUpstreamFlushInterval ,
2022-05-13 22:36:21 +02:00
Timeout : DefaultUpstreamTimeout ,
2020-07-12 16:47:25 +01:00
} ,
2020-05-26 19:56:10 +01:00
2020-07-29 20:08:46 +01:00
LegacyHeaders : LegacyHeaders {
2020-11-07 12:33:37 -08:00
PassBasicAuth : true ,
PassUserHeaders : true ,
SkipAuthStripHeaders : true ,
2020-07-29 20:08:46 +01:00
} ,
2021-02-14 18:47:15 +00:00
LegacyServer : LegacyServer {
HTTPAddress : "127.0.0.1:4180" ,
HTTPSAddress : ":443" ,
} ,
2021-04-03 19:06:30 +03:00
LegacyProvider : LegacyProvider {
2021-04-21 02:33:27 -07:00
ProviderType : "google" ,
AzureTenant : "common" ,
ApprovalPrompt : "force" ,
UserIDClaim : "email" ,
OIDCEmailClaim : "email" ,
OIDCGroupsClaim : "groups" ,
2022-02-15 17:12:22 +01:00
OIDCAudienceClaims : [ ] string { "aud" } ,
OIDCExtraAudiences : [ ] string { } ,
2021-04-21 02:33:27 -07:00
InsecureOIDCSkipNonce : true ,
2021-04-03 19:06:30 +03:00
} ,
2020-05-26 19:56:10 +01:00
Options : * NewOptions ( ) ,
}
}
2020-11-09 20:17:43 +00:00
func NewLegacyFlagSet ( ) * pflag . FlagSet {
flagSet := NewFlagSet ( )
flagSet . AddFlagSet ( legacyUpstreamsFlagSet ( ) )
flagSet . AddFlagSet ( legacyHeadersFlagSet ( ) )
2021-02-14 18:47:15 +00:00
flagSet . AddFlagSet ( legacyServerFlagset ( ) )
2021-04-03 19:06:30 +03:00
flagSet . AddFlagSet ( legacyProviderFlagSet ( ) )
2023-09-04 11:34:54 +02:00
flagSet . AddFlagSet ( legacyGoogleFlagSet ( ) )
2020-11-09 20:17:43 +00:00
return flagSet
}
2020-05-26 19:56:10 +01:00
func ( l * LegacyOptions ) ToOptions ( ) ( * Options , error ) {
2020-07-12 16:47:25 +01:00
upstreams , err := l . LegacyUpstreams . convert ( )
2020-05-26 19:56:10 +01:00
if err != nil {
return nil , fmt . Errorf ( "error converting upstreams: %v" , err )
}
l . Options . UpstreamServers = upstreams
2020-07-29 20:08:46 +01:00
l . Options . InjectRequestHeaders , l . Options . InjectResponseHeaders = l . LegacyHeaders . convert ( )
2021-04-03 19:06:30 +03:00
2021-02-14 18:47:15 +00:00
l . Options . Server , l . Options . MetricsServer = l . LegacyServer . convert ( )
2021-03-21 18:49:30 +00:00
l . Options . LegacyPreferEmailToUser = l . LegacyHeaders . PreferEmailToUser
2021-04-03 19:06:30 +03:00
providers , err := l . LegacyProvider . convert ( )
if err != nil {
return nil , fmt . Errorf ( "error converting provider: %v" , err )
}
l . Options . Providers = providers
2020-05-26 19:56:10 +01:00
return & l . Options , nil
}
2020-07-12 16:47:25 +01:00
type LegacyUpstreams struct {
FlushInterval time . Duration ` flag:"flush-interval" cfg:"flush_interval" `
PassHostHeader bool ` flag:"pass-host-header" cfg:"pass_host_header" `
ProxyWebSockets bool ` flag:"proxy-websockets" cfg:"proxy_websockets" `
SSLUpstreamInsecureSkipVerify bool ` flag:"ssl-upstream-insecure-skip-verify" cfg:"ssl_upstream_insecure_skip_verify" `
Upstreams [ ] string ` flag:"upstream" cfg:"upstreams" `
2022-05-13 22:36:21 +02:00
Timeout time . Duration ` flag:"upstream-timeout" cfg:"upstream_timeout" `
2020-07-12 16:47:25 +01:00
}
func legacyUpstreamsFlagSet ( ) * pflag . FlagSet {
flagSet := pflag . NewFlagSet ( "upstreams" , pflag . ExitOnError )
2020-11-19 10:35:04 +00:00
flagSet . Duration ( "flush-interval" , DefaultUpstreamFlushInterval , "period between response flushing when streaming responses" )
2020-07-12 16:47:25 +01:00
flagSet . Bool ( "pass-host-header" , true , "pass the request Host Header to upstream" )
flagSet . Bool ( "proxy-websockets" , true , "enables WebSocket proxying" )
flagSet . Bool ( "ssl-upstream-insecure-skip-verify" , false , "skip validation of certificates presented when using HTTPS upstreams" )
flagSet . StringSlice ( "upstream" , [ ] string { } , "the http url(s) of the upstream endpoint, file:// paths for static files or static://<status_code> for static response. Routing is based on the path" )
2022-05-13 22:36:21 +02:00
flagSet . Duration ( "upstream-timeout" , DefaultUpstreamTimeout , "maximum amount of time the server will wait for a response from the upstream" )
2020-07-12 16:47:25 +01:00
return flagSet
}
2021-09-17 11:08:18 +00:00
func ( l * LegacyUpstreams ) convert ( ) ( UpstreamConfig , error ) {
upstreams := UpstreamConfig { }
2020-05-26 19:56:10 +01:00
2020-07-12 16:47:25 +01:00
for _ , upstreamString := range l . Upstreams {
2020-05-26 19:56:10 +01:00
u , err := url . Parse ( upstreamString )
if err != nil {
2021-09-17 11:08:18 +00:00
return UpstreamConfig { } , fmt . Errorf ( "could not parse upstream %q: %v" , upstreamString , err )
2020-05-26 19:56:10 +01:00
}
if u . Path == "" {
u . Path = "/"
}
2020-11-11 23:02:00 +00:00
flushInterval := Duration ( l . FlushInterval )
2022-05-13 22:36:21 +02:00
timeout := Duration ( l . Timeout )
2020-05-26 19:56:10 +01:00
upstream := Upstream {
ID : u . Path ,
Path : u . Path ,
URI : upstreamString ,
2020-07-12 16:47:25 +01:00
InsecureSkipTLSVerify : l . SSLUpstreamInsecureSkipVerify ,
2020-07-19 14:00:52 +01:00
PassHostHeader : & l . PassHostHeader ,
ProxyWebSockets : & l . ProxyWebSockets ,
2020-11-11 23:02:00 +00:00
FlushInterval : & flushInterval ,
2022-05-13 22:36:21 +02:00
Timeout : & timeout ,
2020-05-26 19:56:10 +01:00
}
switch u . Scheme {
case "file" :
if u . Fragment != "" {
upstream . ID = u . Fragment
upstream . Path = u . Fragment
2020-08-31 14:05:52 +01:00
// Trim the fragment from the end of the URI
upstream . URI = strings . SplitN ( upstreamString , "#" , 2 ) [ 0 ]
2020-05-26 19:56:10 +01:00
}
case "static" :
responseCode , err := strconv . Atoi ( u . Host )
if err != nil {
2020-08-10 11:44:08 +01:00
logger . Errorf ( "unable to convert %q to int, use default \"200\"" , u . Host )
2020-05-26 19:56:10 +01:00
responseCode = 200
}
upstream . Static = true
upstream . StaticCode = & responseCode
2020-08-31 11:22:10 +01:00
// This is not allowed to be empty and must be unique
2020-05-26 19:56:10 +01:00
upstream . ID = upstreamString
2020-08-31 11:22:10 +01:00
// We only support the root path in the legacy config
upstream . Path = "/"
2020-05-26 19:56:10 +01:00
// Force defaults compatible with static responses
upstream . URI = ""
upstream . InsecureSkipTLSVerify = false
2020-07-19 14:00:52 +01:00
upstream . PassHostHeader = nil
upstream . ProxyWebSockets = nil
2020-08-31 11:22:10 +01:00
upstream . FlushInterval = nil
2022-05-13 22:36:21 +02:00
upstream . Timeout = nil
2020-05-26 19:56:10 +01:00
}
2021-09-17 11:08:18 +00:00
upstreams . Upstreams = append ( upstreams . Upstreams , upstream )
2020-05-26 19:56:10 +01:00
}
return upstreams , nil
}
2020-07-29 20:08:46 +01:00
type LegacyHeaders struct {
PassBasicAuth bool ` flag:"pass-basic-auth" cfg:"pass_basic_auth" `
PassAccessToken bool ` flag:"pass-access-token" cfg:"pass_access_token" `
PassUserHeaders bool ` flag:"pass-user-headers" cfg:"pass_user_headers" `
PassAuthorization bool ` flag:"pass-authorization-header" cfg:"pass_authorization_header" `
SetBasicAuth bool ` flag:"set-basic-auth" cfg:"set_basic_auth" `
SetXAuthRequest bool ` flag:"set-xauthrequest" cfg:"set_xauthrequest" `
SetAuthorization bool ` flag:"set-authorization-header" cfg:"set_authorization_header" `
PreferEmailToUser bool ` flag:"prefer-email-to-user" cfg:"prefer_email_to_user" `
BasicAuthPassword string ` flag:"basic-auth-password" cfg:"basic_auth_password" `
SkipAuthStripHeaders bool ` flag:"skip-auth-strip-headers" cfg:"skip_auth_strip_headers" `
}
func legacyHeadersFlagSet ( ) * pflag . FlagSet {
flagSet := pflag . NewFlagSet ( "headers" , pflag . ExitOnError )
flagSet . Bool ( "pass-basic-auth" , true , "pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream" )
flagSet . Bool ( "pass-access-token" , false , "pass OAuth access_token to upstream via X-Forwarded-Access-Token header" )
flagSet . Bool ( "pass-user-headers" , true , "pass X-Forwarded-User and X-Forwarded-Email information to upstream" )
flagSet . Bool ( "pass-authorization-header" , false , "pass the Authorization Header to upstream" )
flagSet . Bool ( "set-basic-auth" , false , "set HTTP Basic Auth information in response (useful in Nginx auth_request mode)" )
flagSet . Bool ( "set-xauthrequest" , false , "set X-Auth-Request-User and X-Auth-Request-Email response headers (useful in Nginx auth_request mode)" )
flagSet . Bool ( "set-authorization-header" , false , "set Authorization response headers (useful in Nginx auth_request mode)" )
flagSet . Bool ( "prefer-email-to-user" , false , "Prefer to use the Email address as the Username when passing information to upstream. Will only use Username if Email is unavailable, eg. htaccess authentication. Used in conjunction with -pass-basic-auth and -pass-user-headers" )
flagSet . String ( "basic-auth-password" , "" , "the password to set when passing the HTTP Basic Auth header" )
2020-11-07 11:19:30 -08:00
flagSet . Bool ( "skip-auth-strip-headers" , true , "strips X-Forwarded-* style authentication headers & Authorization header if they would be set by oauth2-proxy" )
2020-07-29 20:08:46 +01:00
return flagSet
}
// convert takes the legacy request/response headers and converts them to
// the new format for InjectRequestHeaders and InjectResponseHeaders
func ( l * LegacyHeaders ) convert ( ) ( [ ] Header , [ ] Header ) {
return l . getRequestHeaders ( ) , l . getResponseHeaders ( )
}
func ( l * LegacyHeaders ) getRequestHeaders ( ) [ ] Header {
requestHeaders := [ ] Header { }
if l . PassBasicAuth && l . BasicAuthPassword != "" {
requestHeaders = append ( requestHeaders , getBasicAuthHeader ( l . PreferEmailToUser , l . BasicAuthPassword ) )
}
// In the old implementation, PassUserHeaders is a subset of PassBasicAuth
if l . PassBasicAuth || l . PassUserHeaders {
requestHeaders = append ( requestHeaders , getPassUserHeaders ( l . PreferEmailToUser ) ... )
requestHeaders = append ( requestHeaders , getPreferredUsernameHeader ( ) )
}
if l . PassAccessToken {
requestHeaders = append ( requestHeaders , getPassAccessTokenHeader ( ) )
}
if l . PassAuthorization {
requestHeaders = append ( requestHeaders , getAuthorizationHeader ( ) )
}
for i := range requestHeaders {
requestHeaders [ i ] . PreserveRequestValue = ! l . SkipAuthStripHeaders
}
return requestHeaders
}
func ( l * LegacyHeaders ) getResponseHeaders ( ) [ ] Header {
responseHeaders := [ ] Header { }
if l . SetXAuthRequest {
2020-11-07 12:34:27 -08:00
responseHeaders = append ( responseHeaders , getXAuthRequestHeaders ( ) ... )
if l . PassAccessToken {
responseHeaders = append ( responseHeaders , getXAuthRequestAccessTokenHeader ( ) )
}
2020-07-29 20:08:46 +01:00
}
if l . SetBasicAuth {
responseHeaders = append ( responseHeaders , getBasicAuthHeader ( l . PreferEmailToUser , l . BasicAuthPassword ) )
}
if l . SetAuthorization {
responseHeaders = append ( responseHeaders , getAuthorizationHeader ( ) )
}
return responseHeaders
}
func getBasicAuthHeader ( preferEmailToUser bool , basicAuthPassword string ) Header {
claim := "user"
if preferEmailToUser {
claim = "email"
}
return Header {
Name : "Authorization" ,
Values : [ ] HeaderValue {
{
ClaimSource : & ClaimSource {
2020-11-19 20:06:43 +00:00
Claim : claim ,
Prefix : "Basic " ,
2020-07-29 20:08:46 +01:00
BasicAuthPassword : & SecretSource {
2020-11-19 19:58:50 +00:00
Value : [ ] byte ( basicAuthPassword ) ,
2020-07-29 20:08:46 +01:00
} ,
} ,
} ,
} ,
}
}
func getPassUserHeaders ( preferEmailToUser bool ) [ ] Header {
headers := [ ] Header {
{
Name : "X-Forwarded-Groups" ,
Values : [ ] HeaderValue {
{
ClaimSource : & ClaimSource {
Claim : "groups" ,
} ,
} ,
} ,
} ,
}
if preferEmailToUser {
return append ( headers ,
Header {
Name : "X-Forwarded-User" ,
Values : [ ] HeaderValue {
{
ClaimSource : & ClaimSource {
Claim : "email" ,
} ,
} ,
} ,
} ,
)
}
return append ( headers ,
Header {
Name : "X-Forwarded-User" ,
Values : [ ] HeaderValue {
{
ClaimSource : & ClaimSource {
Claim : "user" ,
} ,
} ,
} ,
} ,
Header {
Name : "X-Forwarded-Email" ,
Values : [ ] HeaderValue {
{
ClaimSource : & ClaimSource {
Claim : "email" ,
} ,
} ,
} ,
} ,
)
}
func getPassAccessTokenHeader ( ) Header {
return Header {
Name : "X-Forwarded-Access-Token" ,
Values : [ ] HeaderValue {
{
ClaimSource : & ClaimSource {
Claim : "access_token" ,
} ,
} ,
} ,
}
}
func getAuthorizationHeader ( ) Header {
return Header {
Name : "Authorization" ,
Values : [ ] HeaderValue {
{
ClaimSource : & ClaimSource {
Claim : "id_token" ,
Prefix : "Bearer " ,
} ,
} ,
} ,
}
}
func getPreferredUsernameHeader ( ) Header {
return Header {
Name : "X-Forwarded-Preferred-Username" ,
Values : [ ] HeaderValue {
{
ClaimSource : & ClaimSource {
Claim : "preferred_username" ,
} ,
} ,
} ,
}
}
2020-11-07 12:34:27 -08:00
func getXAuthRequestHeaders ( ) [ ] Header {
2020-07-29 20:08:46 +01:00
headers := [ ] Header {
{
Name : "X-Auth-Request-User" ,
Values : [ ] HeaderValue {
{
ClaimSource : & ClaimSource {
Claim : "user" ,
} ,
} ,
} ,
} ,
{
Name : "X-Auth-Request-Email" ,
Values : [ ] HeaderValue {
{
ClaimSource : & ClaimSource {
Claim : "email" ,
} ,
} ,
} ,
} ,
{
2020-11-07 12:34:27 -08:00
Name : "X-Auth-Request-Preferred-Username" ,
2020-07-29 20:08:46 +01:00
Values : [ ] HeaderValue {
{
ClaimSource : & ClaimSource {
2020-11-07 12:34:27 -08:00
Claim : "preferred_username" ,
2020-07-29 20:08:46 +01:00
} ,
} ,
} ,
} ,
2020-11-07 12:34:27 -08:00
{
Name : "X-Auth-Request-Groups" ,
2020-07-29 20:08:46 +01:00
Values : [ ] HeaderValue {
{
ClaimSource : & ClaimSource {
2020-11-07 12:34:27 -08:00
Claim : "groups" ,
2020-07-29 20:08:46 +01:00
} ,
} ,
} ,
2020-11-07 12:34:27 -08:00
} ,
2020-07-29 20:08:46 +01:00
}
return headers
}
2020-11-07 12:34:27 -08:00
func getXAuthRequestAccessTokenHeader ( ) Header {
return Header {
Name : "X-Auth-Request-Access-Token" ,
Values : [ ] HeaderValue {
{
ClaimSource : & ClaimSource {
Claim : "access_token" ,
} ,
} ,
} ,
}
}
2021-02-14 18:47:15 +00:00
type LegacyServer struct {
2022-07-13 07:40:31 -07:00
MetricsAddress string ` flag:"metrics-address" cfg:"metrics_address" `
MetricsSecureAddress string ` flag:"metrics-secure-address" cfg:"metrics_secure_address" `
MetricsTLSCertFile string ` flag:"metrics-tls-cert-file" cfg:"metrics_tls_cert_file" `
MetricsTLSKeyFile string ` flag:"metrics-tls-key-file" cfg:"metrics_tls_key_file" `
HTTPAddress string ` flag:"http-address" cfg:"http_address" `
HTTPSAddress string ` flag:"https-address" cfg:"https_address" `
TLSCertFile string ` flag:"tls-cert-file" cfg:"tls_cert_file" `
TLSKeyFile string ` flag:"tls-key-file" cfg:"tls_key_file" `
TLSMinVersion string ` flag:"tls-min-version" cfg:"tls_min_version" `
TLSCipherSuites [ ] string ` flag:"tls-cipher-suite" cfg:"tls_cipher_suites" `
2021-02-14 18:47:15 +00:00
}
func legacyServerFlagset ( ) * pflag . FlagSet {
flagSet := pflag . NewFlagSet ( "server" , pflag . ExitOnError )
flagSet . String ( "metrics-address" , "" , "the address /metrics will be served on (e.g. \":9100\")" )
2021-02-19 11:56:20 +00:00
flagSet . String ( "metrics-secure-address" , "" , "the address /metrics will be served on for HTTPS clients (e.g. \":9100\")" )
flagSet . String ( "metrics-tls-cert-file" , "" , "path to certificate file for secure metrics server" )
flagSet . String ( "metrics-tls-key-file" , "" , "path to private key file for secure metrics server" )
2021-02-14 18:47:15 +00:00
flagSet . String ( "http-address" , "127.0.0.1:4180" , "[http://]<addr>:<port> or unix://<path> to listen on for HTTP clients" )
flagSet . String ( "https-address" , ":443" , "<addr>:<port> to listen on for HTTPS clients" )
flagSet . String ( "tls-cert-file" , "" , "path to certificate file" )
flagSet . String ( "tls-key-file" , "" , "path to private key file" )
2021-12-17 00:01:32 +01:00
flagSet . String ( "tls-min-version" , "" , "minimal TLS version for HTTPS clients (either \"TLS1.2\" or \"TLS1.3\")" )
2022-07-13 07:40:31 -07:00
flagSet . StringSlice ( "tls-cipher-suite" , [ ] string { } , "restricts TLS cipher suites to those listed (e.g. TLS_RSA_WITH_RC4_128_SHA) (may be given multiple times)" )
2021-02-14 18:47:15 +00:00
return flagSet
}
2021-04-03 19:06:30 +03:00
type LegacyProvider struct {
ClientID string ` flag:"client-id" cfg:"client_id" `
ClientSecret string ` flag:"client-secret" cfg:"client_secret" `
ClientSecretFile string ` flag:"client-secret-file" cfg:"client_secret_file" `
2023-09-04 11:34:54 +02:00
KeycloakGroups [ ] string ` flag:"keycloak-group" cfg:"keycloak_groups" `
AzureTenant string ` flag:"azure-tenant" cfg:"azure_tenant" `
AzureGraphGroupField string ` flag:"azure-graph-group-field" cfg:"azure_graph_group_field" `
BitbucketTeam string ` flag:"bitbucket-team" cfg:"bitbucket_team" `
BitbucketRepository string ` flag:"bitbucket-repository" cfg:"bitbucket_repository" `
GitHubOrg string ` flag:"github-org" cfg:"github_org" `
GitHubTeam string ` flag:"github-team" cfg:"github_team" `
GitHubRepo string ` flag:"github-repo" cfg:"github_repo" `
GitHubToken string ` flag:"github-token" cfg:"github_token" `
GitHubUsers [ ] string ` flag:"github-user" cfg:"github_users" `
GitLabGroup [ ] string ` flag:"gitlab-group" cfg:"gitlab_groups" `
GitLabProjects [ ] string ` flag:"gitlab-project" cfg:"gitlab_projects" `
2023-09-08 17:27:15 +02:00
GoogleGroupsLegacy [ ] string ` flag:"google-group" cfg:"google_group" `
GoogleGroups [ ] string ` flag:"google-group" cfg:"google_groups" `
2023-09-04 11:34:54 +02:00
GoogleAdminEmail string ` flag:"google-admin-email" cfg:"google_admin_email" `
GoogleServiceAccountJSON string ` flag:"google-service-account-json" cfg:"google_service_account_json" `
GoogleUseApplicationDefaultCredentials bool ` flag:"google-use-application-default-credentials" cfg:"google_use_application_default_credentials" `
2023-10-24 21:03:16 +02:00
GoogleTargetPrincipal string ` flag:"google-target-principal" cfg:"google_target_principal" `
2021-04-03 19:06:30 +03:00
// These options allow for other providers besides Google, with
// potential overrides.
ProviderType string ` flag:"provider" cfg:"provider" `
ProviderName string ` flag:"provider-display-name" cfg:"provider_display_name" `
ProviderCAFiles [ ] string ` flag:"provider-ca-file" cfg:"provider_ca_files" `
OIDCIssuerURL string ` flag:"oidc-issuer-url" cfg:"oidc_issuer_url" `
InsecureOIDCAllowUnverifiedEmail bool ` flag:"insecure-oidc-allow-unverified-email" cfg:"insecure_oidc_allow_unverified_email" `
InsecureOIDCSkipIssuerVerification bool ` flag:"insecure-oidc-skip-issuer-verification" cfg:"insecure_oidc_skip_issuer_verification" `
2021-04-21 02:33:27 -07:00
InsecureOIDCSkipNonce bool ` flag:"insecure-oidc-skip-nonce" cfg:"insecure_oidc_skip_nonce" `
2021-04-03 19:06:30 +03:00
SkipOIDCDiscovery bool ` flag:"skip-oidc-discovery" cfg:"skip_oidc_discovery" `
OIDCJwksURL string ` flag:"oidc-jwks-url" cfg:"oidc_jwks_url" `
OIDCEmailClaim string ` flag:"oidc-email-claim" cfg:"oidc_email_claim" `
OIDCGroupsClaim string ` flag:"oidc-groups-claim" cfg:"oidc_groups_claim" `
2022-02-15 17:12:22 +01:00
OIDCAudienceClaims [ ] string ` flag:"oidc-audience-claim" cfg:"oidc_audience_claims" `
OIDCExtraAudiences [ ] string ` flag:"oidc-extra-audience" cfg:"oidc_extra_audiences" `
2021-04-03 19:06:30 +03:00
LoginURL string ` flag:"login-url" cfg:"login_url" `
RedeemURL string ` flag:"redeem-url" cfg:"redeem_url" `
ProfileURL string ` flag:"profile-url" cfg:"profile_url" `
ProtectedResource string ` flag:"resource" cfg:"resource" `
ValidateURL string ` flag:"validate-url" cfg:"validate_url" `
Scope string ` flag:"scope" cfg:"scope" `
Prompt string ` flag:"prompt" cfg:"prompt" `
ApprovalPrompt string ` flag:"approval-prompt" cfg:"approval_prompt" ` // Deprecated by OIDC 1.0
UserIDClaim string ` flag:"user-id-claim" cfg:"user_id_claim" `
AllowedGroups [ ] string ` flag:"allowed-group" cfg:"allowed_groups" `
2021-03-14 18:32:24 -07:00
AllowedRoles [ ] string ` flag:"allowed-role" cfg:"allowed_roles" `
2021-04-03 19:06:30 +03:00
AcrValues string ` flag:"acr-values" cfg:"acr_values" `
JWTKey string ` flag:"jwt-key" cfg:"jwt_key" `
JWTKeyFile string ` flag:"jwt-key-file" cfg:"jwt_key_file" `
PubJWKURL string ` flag:"pubjwk-url" cfg:"pubjwk_url" `
2022-03-13 06:08:33 -04:00
// PKCE Code Challenge method to use (either S256 or plain)
2022-09-01 05:58:43 -04:00
CodeChallengeMethod string ` flag:"code-challenge-method" cfg:"code_challenge_method" `
// Provided for legacy reasons, to be dropped in newer version see #1667
ForceCodeChallengeMethod string ` flag:"force-code-challenge-method" cfg:"force_code_challenge_method" `
2021-04-03 19:06:30 +03:00
}
func legacyProviderFlagSet ( ) * pflag . FlagSet {
flagSet := pflag . NewFlagSet ( "provider" , pflag . ExitOnError )
flagSet . StringSlice ( "keycloak-group" , [ ] string { } , "restrict logins to members of these groups (may be given multiple times)" )
flagSet . String ( "azure-tenant" , "common" , "go to a tenant-specific or common (tenant-independent) endpoint." )
2022-02-22 13:32:45 +02:00
flagSet . String ( "azure-graph-group-field" , "" , "configures the group field to be used when building the groups list(`id` or `displayName`. Default is `id`) from Microsoft Graph(available only for v2.0 oidc url). Based on this value, the `allowed-group` config values should be adjusted accordingly. If using `id` as group field, `allowed-group` should contains groups IDs, if using `displayName` as group field, `allowed-group` should contains groups name" )
2021-04-03 19:06:30 +03:00
flagSet . String ( "bitbucket-team" , "" , "restrict logins to members of this team" )
flagSet . String ( "bitbucket-repository" , "" , "restrict logins to user with access to this repository" )
flagSet . String ( "github-org" , "" , "restrict logins to members of this organisation" )
flagSet . String ( "github-team" , "" , "restrict logins to members of this team" )
flagSet . String ( "github-repo" , "" , "restrict logins to collaborators of this repository" )
flagSet . String ( "github-token" , "" , "the token to use when verifying repository collaborators (must have push access to the repository)" )
flagSet . StringSlice ( "github-user" , [ ] string { } , "allow users with these usernames to login even if they do not belong to the specified org and team or collaborators (may be given multiple times)" )
flagSet . StringSlice ( "gitlab-group" , [ ] string { } , "restrict logins to members of this group (may be given multiple times)" )
flagSet . StringSlice ( "gitlab-project" , [ ] string { } , "restrict logins to members of this project (may be given multiple times) (eg `group/project=accesslevel`). Access level should be a value matching Gitlab access levels (see https://docs.gitlab.com/ee/api/members.html#valid-access-levels), defaulted to 20 if absent" )
flagSet . String ( "client-id" , "" , "the OAuth Client ID: ie: \"123456.apps.googleusercontent.com\"" )
flagSet . String ( "client-secret" , "" , "the OAuth Client Secret" )
flagSet . String ( "client-secret-file" , "" , "the file with OAuth Client Secret" )
flagSet . String ( "provider" , "google" , "OAuth provider" )
flagSet . String ( "provider-display-name" , "" , "Provider display name" )
flagSet . StringSlice ( "provider-ca-file" , [ ] string { } , "One or more paths to CA certificates that should be used when connecting to the provider. If not specified, the default Go trust sources are used instead." )
flagSet . String ( "oidc-issuer-url" , "" , "OpenID Connect issuer URL (ie: https://accounts.google.com)" )
flagSet . Bool ( "insecure-oidc-allow-unverified-email" , false , "Don't fail if an email address in an id_token is not verified" )
flagSet . Bool ( "insecure-oidc-skip-issuer-verification" , false , "Do not verify if issuer matches OIDC discovery URL" )
2021-04-21 02:33:27 -07:00
flagSet . Bool ( "insecure-oidc-skip-nonce" , true , "skip verifying the OIDC ID Token's nonce claim" )
2021-04-03 19:06:30 +03:00
flagSet . Bool ( "skip-oidc-discovery" , false , "Skip OIDC discovery and use manually supplied Endpoints" )
flagSet . String ( "oidc-jwks-url" , "" , "OpenID Connect JWKS URL (ie: https://www.googleapis.com/oauth2/v3/certs)" )
2022-02-15 11:07:13 +00:00
flagSet . String ( "oidc-groups-claim" , OIDCGroupsClaim , "which OIDC claim contains the user groups" )
flagSet . String ( "oidc-email-claim" , OIDCEmailClaim , "which OIDC claim contains the user's email" )
flagSet . StringSlice ( "oidc-audience-claim" , OIDCAudienceClaims , "which OIDC claims are used as audience to verify against client id" )
2022-02-15 17:12:22 +01:00
flagSet . StringSlice ( "oidc-extra-audience" , [ ] string { } , "additional audiences allowed to pass audience verification" )
2021-04-03 19:06:30 +03:00
flagSet . String ( "login-url" , "" , "Authentication endpoint" )
flagSet . String ( "redeem-url" , "" , "Token redemption endpoint" )
flagSet . String ( "profile-url" , "" , "Profile access endpoint" )
flagSet . String ( "resource" , "" , "The resource that is protected (Azure AD only)" )
flagSet . String ( "validate-url" , "" , "Access token validation endpoint" )
flagSet . String ( "scope" , "" , "OAuth scope specification" )
flagSet . String ( "prompt" , "" , "OIDC prompt" )
flagSet . String ( "approval-prompt" , "force" , "OAuth approval_prompt" )
2022-03-13 06:08:33 -04:00
flagSet . String ( "code-challenge-method" , "" , "use PKCE code challenges with the specified method. Either 'plain' or 'S256'" )
2022-09-01 05:58:43 -04:00
flagSet . String ( "force-code-challenge-method" , "" , "Deprecated - use --code-challenge-method" )
2021-04-03 19:06:30 +03:00
flagSet . String ( "acr-values" , "" , "acr values string: optional" )
flagSet . String ( "jwt-key" , "" , "private key in PEM format used to sign JWT, so that you can say something like -jwt-key=\"${OAUTH2_PROXY_JWT_KEY}\": required by login.gov" )
flagSet . String ( "jwt-key-file" , "" , "path to the private key file in PEM format used to sign the JWT so that you can say something like -jwt-key-file=/etc/ssl/private/jwt_signing_key.pem: required by login.gov" )
flagSet . String ( "pubjwk-url" , "" , "JWK pubkey access endpoint: required by login.gov" )
2022-02-15 11:07:13 +00:00
flagSet . String ( "user-id-claim" , OIDCEmailClaim , "(DEPRECATED for `oidc-email-claim`) which claim contains the user ID" )
2021-04-03 19:06:30 +03:00
flagSet . StringSlice ( "allowed-group" , [ ] string { } , "restrict logins to members of this group (may be given multiple times)" )
2021-03-14 18:32:24 -07:00
flagSet . StringSlice ( "allowed-role" , [ ] string { } , "(keycloak-oidc) restrict logins to members of these roles (may be given multiple times)" )
2021-04-03 19:06:30 +03:00
return flagSet
}
2023-09-04 11:34:54 +02:00
func legacyGoogleFlagSet ( ) * pflag . FlagSet {
flagSet := pflag . NewFlagSet ( "google" , pflag . ExitOnError )
flagSet . StringSlice ( "google-group" , [ ] string { } , "restrict logins to members of this google group (may be given multiple times)." )
flagSet . String ( "google-admin-email" , "" , "the google admin to impersonate for api calls" )
flagSet . String ( "google-service-account-json" , "" , "the path to the service account json credentials" )
flagSet . String ( "google-use-application-default-credentials" , "" , "use application default credentials instead of service account json (i.e. GKE Workload Identity)" )
2023-10-24 21:03:16 +02:00
flagSet . String ( "google-target-principal" , "" , "the targetprincipal to impersonate when using ADC" )
2023-09-04 11:34:54 +02:00
return flagSet
}
2021-02-14 18:47:15 +00:00
func ( l LegacyServer ) convert ( ) ( Server , Server ) {
appServer := Server {
BindAddress : l . HTTPAddress ,
SecureBindAddress : l . HTTPSAddress ,
}
if l . TLSKeyFile != "" || l . TLSCertFile != "" {
appServer . TLS = & TLS {
Key : & SecretSource {
FromFile : l . TLSKeyFile ,
} ,
Cert : & SecretSource {
FromFile : l . TLSCertFile ,
} ,
2021-12-17 00:01:32 +01:00
MinVersion : l . TLSMinVersion ,
2021-02-14 18:47:15 +00:00
}
2022-07-13 07:40:31 -07:00
if len ( l . TLSCipherSuites ) != 0 {
appServer . TLS . CipherSuites = l . TLSCipherSuites
}
2021-02-14 18:47:15 +00:00
// Preserve backwards compatibility, only run one server
appServer . BindAddress = ""
} else {
// Disable the HTTPS server if there's no certificates.
// This preserves backwards compatibility.
appServer . SecureBindAddress = ""
}
metricsServer := Server {
2021-02-19 11:56:20 +00:00
BindAddress : l . MetricsAddress ,
SecureBindAddress : l . MetricsSecureAddress ,
}
if l . MetricsTLSKeyFile != "" || l . MetricsTLSCertFile != "" {
metricsServer . TLS = & TLS {
Key : & SecretSource {
FromFile : l . MetricsTLSKeyFile ,
} ,
Cert : & SecretSource {
FromFile : l . MetricsTLSCertFile ,
} ,
}
2021-02-14 18:47:15 +00:00
}
return appServer , metricsServer
}
2021-04-03 19:06:30 +03:00
func ( l * LegacyProvider ) convert ( ) ( Providers , error ) {
providers := Providers { }
provider := Provider {
2022-03-13 06:08:33 -04:00
ClientID : l . ClientID ,
ClientSecret : l . ClientSecret ,
ClientSecretFile : l . ClientSecretFile ,
Type : ProviderType ( l . ProviderType ) ,
CAFiles : l . ProviderCAFiles ,
LoginURL : l . LoginURL ,
RedeemURL : l . RedeemURL ,
ProfileURL : l . ProfileURL ,
ProtectedResource : l . ProtectedResource ,
ValidateURL : l . ValidateURL ,
Scope : l . Scope ,
AllowedGroups : l . AllowedGroups ,
CodeChallengeMethod : l . CodeChallengeMethod ,
2021-04-03 19:06:30 +03:00
}
// This part is out of the switch section for all providers that support OIDC
provider . OIDCConfig = OIDCOptions {
IssuerURL : l . OIDCIssuerURL ,
InsecureAllowUnverifiedEmail : l . InsecureOIDCAllowUnverifiedEmail ,
InsecureSkipIssuerVerification : l . InsecureOIDCSkipIssuerVerification ,
2021-04-21 02:33:27 -07:00
InsecureSkipNonce : l . InsecureOIDCSkipNonce ,
2021-04-03 19:06:30 +03:00
SkipDiscovery : l . SkipOIDCDiscovery ,
JwksURL : l . OIDCJwksURL ,
UserIDClaim : l . UserIDClaim ,
EmailClaim : l . OIDCEmailClaim ,
GroupsClaim : l . OIDCGroupsClaim ,
2022-02-15 17:12:22 +01:00
AudienceClaims : l . OIDCAudienceClaims ,
ExtraAudiences : l . OIDCExtraAudiences ,
2021-04-03 19:06:30 +03:00
}
2022-09-01 05:58:43 -04:00
// Support for legacy configuration option
if l . ForceCodeChallengeMethod != "" && l . CodeChallengeMethod == "" {
provider . CodeChallengeMethod = l . ForceCodeChallengeMethod
}
2021-04-03 19:06:30 +03:00
// This part is out of the switch section because azure has a default tenant
// that needs to be added from legacy options
provider . AzureConfig = AzureOptions {
2022-02-22 13:32:45 +02:00
Tenant : l . AzureTenant ,
GraphGroupField : l . AzureGraphGroupField ,
2021-04-03 19:06:30 +03:00
}
switch provider . Type {
case "github" :
provider . GitHubConfig = GitHubOptions {
Org : l . GitHubOrg ,
Team : l . GitHubTeam ,
Repo : l . GitHubRepo ,
Token : l . GitHubToken ,
Users : l . GitHubUsers ,
}
2021-05-05 16:18:02 +02:00
case "keycloak-oidc" :
2021-04-03 19:06:30 +03:00
provider . KeycloakConfig = KeycloakOptions {
Groups : l . KeycloakGroups ,
2021-03-14 18:32:24 -07:00
Roles : l . AllowedRoles ,
2021-04-03 19:06:30 +03:00
}
2021-05-05 16:18:02 +02:00
case "keycloak" :
provider . KeycloakConfig = KeycloakOptions {
Groups : l . KeycloakGroups ,
}
2021-04-03 19:06:30 +03:00
case "gitlab" :
provider . GitLabConfig = GitLabOptions {
Group : l . GitLabGroup ,
Projects : l . GitLabProjects ,
}
case "login.gov" :
provider . LoginGovConfig = LoginGovOptions {
JWTKey : l . JWTKey ,
JWTKeyFile : l . JWTKeyFile ,
PubJWKURL : l . PubJWKURL ,
}
case "bitbucket" :
provider . BitbucketConfig = BitbucketOptions {
Team : l . BitbucketTeam ,
Repository : l . BitbucketRepository ,
}
case "google" :
2023-09-08 17:27:15 +02:00
if len ( l . GoogleGroupsLegacy ) != 0 && ! reflect . DeepEqual ( l . GoogleGroupsLegacy , l . GoogleGroups ) {
// Log the deprecation notice
logger . Error (
"WARNING: The 'OAUTH2_PROXY_GOOGLE_GROUP' environment variable is deprecated and will likely be removed in the next major release. Use 'OAUTH2_PROXY_GOOGLE_GROUPS' instead." ,
)
l . GoogleGroups = l . GoogleGroupsLegacy
}
2021-04-03 19:06:30 +03:00
provider . GoogleConfig = GoogleOptions {
2023-09-04 11:34:54 +02:00
Groups : l . GoogleGroups ,
AdminEmail : l . GoogleAdminEmail ,
ServiceAccountJSON : l . GoogleServiceAccountJSON ,
UseApplicationDefaultCredentials : l . GoogleUseApplicationDefaultCredentials ,
2023-10-24 21:03:16 +02:00
TargetPrincipal : l . GoogleTargetPrincipal ,
2021-04-03 19:06:30 +03:00
}
}
if l . ProviderName != "" {
provider . ID = l . ProviderName
provider . Name = l . ProviderName
} else {
provider . ID = l . ProviderType + "=" + l . ClientID
}
2022-02-16 16:18:51 +00:00
// handle AcrValues, Prompt and ApprovalPrompt
var urlParams [ ] LoginURLParameter
if l . AcrValues != "" {
urlParams = append ( urlParams , LoginURLParameter { Name : "acr_values" , Default : [ ] string { l . AcrValues } } )
}
switch {
case l . Prompt != "" :
urlParams = append ( urlParams , LoginURLParameter { Name : "prompt" , Default : [ ] string { l . Prompt } } )
case l . ApprovalPrompt != "" :
urlParams = append ( urlParams , LoginURLParameter { Name : "approval_prompt" , Default : [ ] string { l . ApprovalPrompt } } )
default :
// match legacy behaviour by default - if neither prompt nor approval_prompt
// specified, use approval_prompt=force
urlParams = append ( urlParams , LoginURLParameter { Name : "approval_prompt" , Default : [ ] string { "force" } } )
}
provider . LoginURLParameters = urlParams
2021-04-03 19:06:30 +03:00
providers = append ( providers , provider )
return providers , nil
}