2014-11-09 19:51:10 +00:00
package main
import (
"fmt"
"net/url"
2015-01-12 09:18:41 +00:00
"regexp"
2015-03-15 16:23:13 +00:00
"strings"
2015-01-19 16:10:37 +00:00
"time"
2015-03-30 19:48:30 +00:00
2015-05-21 06:50:21 +00:00
"github.com/bitly/oauth2_proxy/providers"
2014-11-09 19:51:10 +00:00
)
// Configuration Options that can be set by Command Line Flag, or Config File
type Options struct {
2015-05-29 22:47:40 +00:00
ProxyPrefix string ` flag:"proxy-prefix" cfg:"proxy-prefix" `
2015-03-17 19:15:15 +00:00
HttpAddress string ` flag:"http-address" cfg:"http_address" `
2015-06-08 01:51:47 +00:00
HttpsAddress string ` flag:"https-address" cfg:"https_address" `
2015-03-17 19:15:15 +00:00
RedirectUrl string ` flag:"redirect-url" cfg:"redirect_url" `
2015-05-21 06:50:21 +00:00
ClientID string ` flag:"client-id" cfg:"client_id" env:"OAUTH2_PROXY_CLIENT_ID" `
ClientSecret string ` flag:"client-secret" cfg:"client_secret" env:"OAUTH2_PROXY_CLIENT_SECRET" `
2015-06-08 01:51:47 +00:00
TLSCertFile string ` flag:"tls-cert" cfg:"tls_cert_file" `
TLSKeyFile string ` flag:"tls-key" cfg:"tls_key_file" `
2015-03-17 19:15:15 +00:00
AuthenticatedEmailsFile string ` flag:"authenticated-emails-file" cfg:"authenticated_emails_file" `
2015-06-06 18:37:54 +00:00
EmailDomains [ ] string ` flag:"email-domain" cfg:"email_domains" `
2015-05-21 03:23:48 +00:00
GitHubOrg string ` flag:"github-org" cfg:"github_org" `
GitHubTeam string ` flag:"github-team" cfg:"github_team" `
2015-03-17 19:15:15 +00:00
HtpasswdFile string ` flag:"htpasswd-file" cfg:"htpasswd_file" `
DisplayHtpasswdForm bool ` flag:"display-htpasswd-form" cfg:"display_htpasswd_form" `
2015-03-17 22:06:06 +00:00
CustomTemplatesDir string ` flag:"custom-templates-dir" cfg:"custom_templates_dir" `
2015-03-17 19:15:15 +00:00
2015-06-08 03:52:28 +00:00
CookieName string ` flag:"cookie-name" cfg:"cookie_name" env:"OAUTH2_PROXY_COOKIE_NAME" `
CookieSecret string ` flag:"cookie-secret" cfg:"cookie_secret" env:"OAUTH2_PROXY_COOKIE_SECRET" `
CookieDomain string ` flag:"cookie-domain" cfg:"cookie_domain" env:"OAUTH2_PROXY_COOKIE_DOMAIN" `
CookieExpire time . Duration ` flag:"cookie-expire" cfg:"cookie_expire" env:"OAUTH2_PROXY_COOKIE_EXPIRE" `
CookieRefresh time . Duration ` flag:"cookie-refresh" cfg:"cookie_refresh" env:"OAUTH2_PROXY_COOKIE_REFRESH" `
CookieSecure bool ` flag:"cookie-secure" cfg:"cookie_secure" `
CookieHttpOnly bool ` flag:"cookie-httponly" cfg:"cookie_httponly" `
2015-03-17 19:15:15 +00:00
2015-07-24 09:17:43 +00:00
Upstreams [ ] string ` flag:"upstream" cfg:"upstreams" `
SkipAuthRegex [ ] string ` flag:"skip-auth-regex" cfg:"skip_auth_regex" `
PassBasicAuth bool ` flag:"pass-basic-auth" cfg:"pass_basic_auth" `
BasicAuthPassword string ` flag:"basic-auth-password" cfg:"basic_auth_password" `
PassAccessToken bool ` flag:"pass-access-token" cfg:"pass_access_token" `
PassHostHeader bool ` flag:"pass-host-header" cfg:"pass_host_header" `
2014-11-09 19:51:10 +00:00
2015-03-30 19:48:30 +00:00
// These options allow for other providers besides Google, with
// potential overrides.
2015-07-25 23:27:49 +00:00
Provider string ` flag:"provider" cfg:"provider" `
LoginUrl string ` flag:"login-url" cfg:"login_url" `
RedeemUrl string ` flag:"redeem-url" cfg:"redeem_url" `
ProfileUrl string ` flag:"profile-url" cfg:"profile_url" `
ValidateUrl string ` flag:"validate-url" cfg:"validate_url" `
Scope string ` flag:"scope" cfg:"scope" `
ApprovalPrompt string ` flag:"approval-prompt" cfg:"approval_prompt" `
2015-03-30 19:48:30 +00:00
2015-03-19 20:37:16 +00:00
RequestLogging bool ` flag:"request-logging" cfg:"request_logging" `
2014-11-09 19:51:10 +00:00
// internal values that are set after config validation
2015-01-19 16:10:37 +00:00
redirectUrl * url . URL
proxyUrls [ ] * url . URL
2015-01-12 09:18:41 +00:00
CompiledRegex [ ] * regexp . Regexp
2015-03-30 19:48:30 +00:00
provider providers . Provider
2014-11-09 19:51:10 +00:00
}
func NewOptions ( ) * Options {
2014-11-10 03:21:46 +00:00
return & Options {
2015-05-29 22:47:40 +00:00
ProxyPrefix : "/oauth2" ,
2014-12-09 20:38:57 +00:00
HttpAddress : "127.0.0.1:4180" ,
2015-06-08 01:51:47 +00:00
HttpsAddress : ":443" ,
2014-12-09 20:38:57 +00:00
DisplayHtpasswdForm : true ,
2015-06-08 03:52:28 +00:00
CookieName : "_oauth2_proxy" ,
2015-03-18 03:13:45 +00:00
CookieSecure : true ,
2015-01-19 15:52:18 +00:00
CookieHttpOnly : true ,
2014-12-09 20:38:57 +00:00
CookieExpire : time . Duration ( 168 ) * time . Hour ,
2015-05-08 14:00:57 +00:00
CookieRefresh : time . Duration ( 0 ) ,
2015-03-17 19:15:15 +00:00
PassBasicAuth : true ,
2015-04-03 00:57:17 +00:00
PassAccessToken : false ,
2015-03-17 19:15:15 +00:00
PassHostHeader : true ,
2015-07-25 23:27:49 +00:00
ApprovalPrompt : "force" ,
2015-03-19 20:37:16 +00:00
RequestLogging : true ,
2014-11-10 03:21:46 +00:00
}
2014-11-09 19:51:10 +00:00
}
2015-03-30 19:48:30 +00:00
func parseUrl ( to_parse string , urltype string , msgs [ ] string ) ( * url . URL , [ ] string ) {
parsed , err := url . Parse ( to_parse )
if err != nil {
return nil , append ( msgs , fmt . Sprintf (
"error parsing %s-url=%q %s" , urltype , to_parse , err ) )
}
return parsed , msgs
}
2014-11-09 19:51:10 +00:00
func ( o * Options ) Validate ( ) error {
2015-03-15 16:23:13 +00:00
msgs := make ( [ ] string , 0 )
2014-11-09 19:51:10 +00:00
if len ( o . Upstreams ) < 1 {
2015-03-15 16:23:13 +00:00
msgs = append ( msgs , "missing setting: upstream" )
2014-11-09 19:51:10 +00:00
}
if o . CookieSecret == "" {
2015-03-15 16:23:13 +00:00
msgs = append ( msgs , "missing setting: cookie-secret" )
2014-11-09 19:51:10 +00:00
}
if o . ClientID == "" {
2015-03-15 16:23:13 +00:00
msgs = append ( msgs , "missing setting: client-id" )
2014-11-09 19:51:10 +00:00
}
if o . ClientSecret == "" {
2015-03-15 16:23:13 +00:00
msgs = append ( msgs , "missing setting: client-secret" )
2014-11-09 19:51:10 +00:00
}
2015-07-24 20:09:33 +00:00
if o . AuthenticatedEmailsFile == "" && len ( o . EmailDomains ) == 0 && o . HtpasswdFile == "" {
msgs = append ( msgs , "missing setting for email validation: email-domain or authenticated-emails-file required.\n use email-domain=* to authorize all email addresses" )
}
2014-11-09 19:51:10 +00:00
2015-03-30 19:48:30 +00:00
o . redirectUrl , msgs = parseUrl ( o . RedirectUrl , "redirect" , msgs )
2014-11-09 19:51:10 +00:00
for _ , u := range o . Upstreams {
upstreamUrl , err := url . Parse ( u )
if err != nil {
2015-03-15 16:23:13 +00:00
msgs = append ( msgs , fmt . Sprintf (
"error parsing upstream=%q %s" ,
upstreamUrl , err ) )
2014-11-09 19:51:10 +00:00
}
if upstreamUrl . Path == "" {
upstreamUrl . Path = "/"
}
o . proxyUrls = append ( o . proxyUrls , upstreamUrl )
}
2015-01-12 09:18:41 +00:00
for _ , u := range o . SkipAuthRegex {
CompiledRegex , err := regexp . Compile ( u )
if err != nil {
2015-03-15 16:23:13 +00:00
msgs = append ( msgs , fmt . Sprintf (
"error compiling regex=%q %s" , u , err ) )
2015-01-12 09:18:41 +00:00
}
o . CompiledRegex = append ( o . CompiledRegex , CompiledRegex )
}
2015-03-30 19:48:30 +00:00
msgs = parseProviderInfo ( o , msgs )
2015-01-12 09:18:41 +00:00
2015-05-09 21:31:13 +00:00
if o . PassAccessToken || ( o . CookieRefresh != time . Duration ( 0 ) ) {
2015-04-05 13:43:40 +00:00
valid_cookie_secret_size := false
for _ , i := range [ ] int { 16 , 24 , 32 } {
if len ( o . CookieSecret ) == i {
valid_cookie_secret_size = true
}
}
if valid_cookie_secret_size == false {
msgs = append ( msgs , fmt . Sprintf (
"cookie_secret must be 16, 24, or 32 bytes " +
"to create an AES cipher when " +
2015-05-09 21:31:13 +00:00
"pass_access_token == true or " +
"cookie_refresh != 0, but is %d bytes" ,
2015-04-05 13:43:40 +00:00
len ( o . CookieSecret ) ) )
}
}
2015-05-09 21:16:19 +00:00
if o . CookieRefresh >= o . CookieExpire {
msgs = append ( msgs , fmt . Sprintf (
"cookie_refresh (%s) must be less than " +
"cookie_expire (%s)" ,
o . CookieRefresh . String ( ) ,
o . CookieExpire . String ( ) ) )
}
2015-03-15 16:23:13 +00:00
if len ( msgs ) != 0 {
return fmt . Errorf ( "Invalid configuration:\n %s" ,
strings . Join ( msgs , "\n " ) )
}
2014-11-09 19:51:10 +00:00
return nil
}
2015-03-30 19:48:30 +00:00
func parseProviderInfo ( o * Options , msgs [ ] string ) [ ] string {
2015-07-25 23:27:49 +00:00
p := & providers . ProviderData {
Scope : o . Scope ,
ClientID : o . ClientID ,
ClientSecret : o . ClientSecret ,
ApprovalPrompt : o . ApprovalPrompt ,
}
2015-03-30 19:48:30 +00:00
p . LoginUrl , msgs = parseUrl ( o . LoginUrl , "login" , msgs )
p . RedeemUrl , msgs = parseUrl ( o . RedeemUrl , "redeem" , msgs )
p . ProfileUrl , msgs = parseUrl ( o . ProfileUrl , "profile" , msgs )
2015-05-08 21:13:35 +00:00
p . ValidateUrl , msgs = parseUrl ( o . ValidateUrl , "validate" , msgs )
2015-05-21 03:23:48 +00:00
2015-03-30 19:48:30 +00:00
o . provider = providers . New ( o . Provider , p )
2015-05-21 03:23:48 +00:00
switch p := o . provider . ( type ) {
case * providers . GitHubProvider :
p . SetOrgTeam ( o . GitHubOrg , o . GitHubTeam )
}
2015-03-30 19:48:30 +00:00
return msgs
}