2014-11-09 14:51:10 -05:00
package main
import (
"fmt"
"net/url"
2015-01-12 14:48:41 +05:30
"regexp"
2015-03-15 12:23:13 -04:00
"strings"
2015-01-19 16:10:37 +00:00
"time"
2015-03-30 15:48:30 -04:00
"github.com/bitly/google_auth_proxy/providers"
2014-11-09 14:51:10 -05:00
)
// Configuration Options that can be set by Command Line Flag, or Config File
type Options struct {
2015-03-17 15:15:15 -04:00
HttpAddress string ` flag:"http-address" cfg:"http_address" `
RedirectUrl string ` flag:"redirect-url" cfg:"redirect_url" `
ClientID string ` flag:"client-id" cfg:"client_id" env:"GOOGLE_AUTH_PROXY_CLIENT_ID" `
ClientSecret string ` flag:"client-secret" cfg:"client_secret" env:"GOOGLE_AUTH_PROXY_CLIENT_SECRET" `
AuthenticatedEmailsFile string ` flag:"authenticated-emails-file" cfg:"authenticated_emails_file" `
GoogleAppsDomains [ ] string ` flag:"google-apps-domain" cfg:"google_apps_domains" `
HtpasswdFile string ` flag:"htpasswd-file" cfg:"htpasswd_file" `
DisplayHtpasswdForm bool ` flag:"display-htpasswd-form" cfg:"display_htpasswd_form" `
2015-03-17 18:06:06 -04:00
CustomTemplatesDir string ` flag:"custom-templates-dir" cfg:"custom_templates_dir" `
2015-03-17 15:15:15 -04:00
CookieSecret string ` flag:"cookie-secret" cfg:"cookie_secret" env:"GOOGLE_AUTH_PROXY_COOKIE_SECRET" `
CookieDomain string ` flag:"cookie-domain" cfg:"cookie_domain" env:"GOOGLE_AUTH_PROXY_COOKIE_DOMAIN" `
CookieExpire time . Duration ` flag:"cookie-expire" cfg:"cookie_expire" env:"GOOGLE_AUTH_PROXY_COOKIE_EXPIRE" `
2015-03-17 23:13:45 -04:00
CookieHttpsOnly bool ` flag:"cookie-https-only" cfg:"cookie_https_only" ` // deprecated use cookie-secure
CookieSecure bool ` flag:"cookie-secure" cfg:"cookie_secure" `
2015-03-17 15:15:15 -04:00
CookieHttpOnly bool ` flag:"cookie-httponly" cfg:"cookie_httponly" `
2015-04-02 20:57:17 -04: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" `
PassAccessToken bool ` flag:"pass-access-token" cfg:"pass_access_token" `
PassHostHeader bool ` flag:"pass-host-header" cfg:"pass_host_header" `
2014-11-09 14:51:10 -05:00
2015-03-30 15:48:30 -04:00
// These options allow for other providers besides Google, with
// potential overrides.
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" `
Scope string ` flag:"scope" cfg:"scope" `
2015-03-19 16:37:16 -04:00
RequestLogging bool ` flag:"request-logging" cfg:"request_logging" `
2014-11-09 14:51:10 -05: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 14:48:41 +05:30
CompiledRegex [ ] * regexp . Regexp
2015-03-30 15:48:30 -04:00
provider providers . Provider
2014-11-09 14:51:10 -05:00
}
func NewOptions ( ) * Options {
2014-11-09 22:21:46 -05:00
return & Options {
2014-12-09 14:38:57 -06:00
HttpAddress : "127.0.0.1:4180" ,
DisplayHtpasswdForm : true ,
CookieHttpsOnly : true ,
2015-03-17 23:13:45 -04:00
CookieSecure : true ,
2015-01-19 15:52:18 +00:00
CookieHttpOnly : true ,
2014-12-09 14:38:57 -06:00
CookieExpire : time . Duration ( 168 ) * time . Hour ,
2015-03-17 15:15:15 -04:00
PassBasicAuth : true ,
2015-04-02 20:57:17 -04:00
PassAccessToken : false ,
2015-03-17 15:15:15 -04:00
PassHostHeader : true ,
2015-03-19 16:37:16 -04:00
RequestLogging : true ,
2014-11-09 22:21:46 -05:00
}
2014-11-09 14:51:10 -05:00
}
2015-03-30 15:48:30 -04: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 14:51:10 -05:00
func ( o * Options ) Validate ( ) error {
2015-03-15 12:23:13 -04:00
msgs := make ( [ ] string , 0 )
2014-11-09 14:51:10 -05:00
if len ( o . Upstreams ) < 1 {
2015-03-15 12:23:13 -04:00
msgs = append ( msgs , "missing setting: upstream" )
2014-11-09 14:51:10 -05:00
}
if o . CookieSecret == "" {
2015-03-15 12:23:13 -04:00
msgs = append ( msgs , "missing setting: cookie-secret" )
2014-11-09 14:51:10 -05:00
}
if o . ClientID == "" {
2015-03-15 12:23:13 -04:00
msgs = append ( msgs , "missing setting: client-id" )
2014-11-09 14:51:10 -05:00
}
if o . ClientSecret == "" {
2015-03-15 12:23:13 -04:00
msgs = append ( msgs , "missing setting: client-secret" )
2014-11-09 14:51:10 -05:00
}
2015-03-30 15:48:30 -04:00
o . redirectUrl , msgs = parseUrl ( o . RedirectUrl , "redirect" , msgs )
2014-11-09 14:51:10 -05:00
for _ , u := range o . Upstreams {
upstreamUrl , err := url . Parse ( u )
if err != nil {
2015-03-15 12:23:13 -04:00
msgs = append ( msgs , fmt . Sprintf (
"error parsing upstream=%q %s" ,
upstreamUrl , err ) )
2014-11-09 14:51:10 -05:00
}
if upstreamUrl . Path == "" {
upstreamUrl . Path = "/"
}
o . proxyUrls = append ( o . proxyUrls , upstreamUrl )
}
2015-01-12 14:48:41 +05:30
for _ , u := range o . SkipAuthRegex {
CompiledRegex , err := regexp . Compile ( u )
if err != nil {
2015-03-15 12:23:13 -04:00
msgs = append ( msgs , fmt . Sprintf (
"error compiling regex=%q %s" , u , err ) )
2015-01-12 14:48:41 +05:30
}
o . CompiledRegex = append ( o . CompiledRegex , CompiledRegex )
}
2015-03-30 15:48:30 -04:00
msgs = parseProviderInfo ( o , msgs )
2015-01-12 14:48:41 +05:30
2015-04-05 09:43:40 -04:00
if o . PassAccessToken {
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 " +
"pass_access_token == true, " +
"but is %d bytes" ,
len ( o . CookieSecret ) ) )
}
}
2015-03-15 12:23:13 -04:00
if len ( msgs ) != 0 {
return fmt . Errorf ( "Invalid configuration:\n %s" ,
strings . Join ( msgs , "\n " ) )
}
2014-11-09 14:51:10 -05:00
return nil
}
2015-03-30 15:48:30 -04:00
func parseProviderInfo ( o * Options , msgs [ ] string ) [ ] string {
p := & providers . ProviderData { Scope : o . Scope }
p . LoginUrl , msgs = parseUrl ( o . LoginUrl , "login" , msgs )
p . RedeemUrl , msgs = parseUrl ( o . RedeemUrl , "redeem" , msgs )
p . ProfileUrl , msgs = parseUrl ( o . ProfileUrl , "profile" , msgs )
o . provider = providers . New ( o . Provider , p )
return msgs
}