2012-12-10 20:59:23 -05:00
package main
import (
"encoding/base64"
"errors"
"fmt"
2015-03-17 18:06:06 -04:00
"html/template"
2012-12-10 20:59:23 -05:00
"log"
2015-03-19 15:59:48 -04:00
"net"
2012-12-10 20:59:23 -05:00
"net/http"
"net/http/httputil"
"net/url"
2015-01-19 16:10:37 +00:00
"regexp"
2012-12-10 20:59:23 -05:00
"strings"
"time"
2014-08-07 16:16:39 -04:00
2015-06-23 07:23:39 -04:00
"github.com/bitly/oauth2_proxy/cookie"
2015-05-21 02:50:21 -04:00
"github.com/bitly/oauth2_proxy/providers"
2012-12-10 20:59:23 -05:00
)
type OauthProxy struct {
2015-03-17 23:13:45 -04:00
CookieSeed string
2015-06-07 23:52:28 -04:00
CookieName string
2015-03-17 23:13:45 -04:00
CookieDomain string
CookieSecure bool
CookieHttpOnly bool
CookieExpire time . Duration
2015-05-08 10:00:57 -04:00
CookieRefresh time . Duration
2015-03-17 23:13:45 -04:00
Validator func ( string ) bool
2012-12-10 20:59:23 -05:00
2015-05-29 15:47:40 -07:00
RobotsPath string
PingPath string
SignInPath string
OauthStartPath string
OauthCallbackPath string
2014-12-09 14:38:57 -06:00
redirectUrl * url . URL // the url to receive requests at
2015-03-30 15:48:30 -04:00
provider providers . Provider
2015-05-29 15:47:40 -07:00
ProxyPrefix string
2014-12-09 14:38:57 -06:00
SignInMessage string
HtpasswdFile * HtpasswdFile
DisplayHtpasswdForm bool
2015-03-19 16:37:16 -04:00
serveMux http . Handler
2014-12-09 14:38:57 -06:00
PassBasicAuth bool
2015-05-09 16:08:55 -04:00
PassAccessToken bool
2015-06-23 07:23:39 -04:00
CookieCipher * cookie . Cipher
2015-01-12 14:48:41 +05:30
skipAuthRegex [ ] string
compiledRegex [ ] * regexp . Regexp
2015-03-17 18:06:06 -04:00
templates * template . Template
2012-12-10 20:59:23 -05:00
}
2015-03-19 16:37:16 -04:00
type UpstreamProxy struct {
upstream string
handler http . Handler
}
func ( u * UpstreamProxy ) ServeHTTP ( w http . ResponseWriter , r * http . Request ) {
w . Header ( ) . Set ( "GAP-Upstream-Address" , u . upstream )
u . handler . ServeHTTP ( w , r )
}
2014-11-30 17:12:33 -08:00
func NewReverseProxy ( target * url . URL ) ( proxy * httputil . ReverseProxy ) {
2015-03-17 15:15:15 -04:00
return httputil . NewSingleHostReverseProxy ( target )
}
func setProxyUpstreamHostHeader ( proxy * httputil . ReverseProxy , target * url . URL ) {
director := proxy . Director
proxy . Director = func ( req * http . Request ) {
director ( req )
2015-03-17 17:17:40 -04:00
// use RequestURI so that we aren't unescaping encoded slashes in the request path
2015-03-21 15:29:07 -04:00
req . Host = target . Host
req . URL . Opaque = req . RequestURI
2015-03-17 17:17:40 -04:00
req . URL . RawQuery = ""
}
}
func setProxyDirector ( proxy * httputil . ReverseProxy ) {
director := proxy . Director
proxy . Director = func ( req * http . Request ) {
director ( req )
// use RequestURI so that we aren't unescaping encoded slashes in the request path
2015-03-21 15:29:07 -04:00
req . URL . Opaque = req . RequestURI
2015-03-17 17:17:40 -04:00
req . URL . RawQuery = ""
2015-03-17 15:15:15 -04:00
}
2014-11-30 17:12:33 -08:00
}
2014-11-09 14:51:10 -05:00
func NewOauthProxy ( opts * Options , validator func ( string ) bool ) * OauthProxy {
2012-12-10 20:59:23 -05:00
serveMux := http . NewServeMux ( )
2014-11-09 14:51:10 -05:00
for _ , u := range opts . proxyUrls {
2012-12-10 20:59:23 -05:00
path := u . Path
u . Path = ""
2014-11-09 14:51:10 -05:00
log . Printf ( "mapping path %q => upstream %q" , path , u )
2015-03-17 15:15:15 -04:00
proxy := NewReverseProxy ( u )
if ! opts . PassHostHeader {
setProxyUpstreamHostHeader ( proxy , u )
2015-03-17 17:17:40 -04:00
} else {
setProxyDirector ( proxy )
2015-03-17 15:15:15 -04:00
}
2015-03-19 16:37:16 -04:00
serveMux . Handle ( path , & UpstreamProxy { u . Host , proxy } )
2012-12-10 20:59:23 -05:00
}
2015-01-12 14:48:41 +05:30
for _ , u := range opts . CompiledRegex {
log . Printf ( "compiled skip-auth-regex => %q" , u )
}
2014-11-09 14:51:10 -05:00
redirectUrl := opts . redirectUrl
2015-05-29 15:47:40 -07:00
redirectUrl . Path = fmt . Sprintf ( "%s/callback" , opts . ProxyPrefix )
2012-12-10 20:59:23 -05:00
2015-06-07 21:51:47 -04:00
log . Printf ( "OauthProxy configured for %s Client ID: %s" , opts . provider . Data ( ) . ProviderName , opts . ClientID )
2014-11-09 22:21:46 -05:00
domain := opts . CookieDomain
if domain == "" {
domain = "<default>"
}
2015-06-22 15:10:08 -04:00
refresh := "disabled"
if opts . CookieRefresh != time . Duration ( 0 ) {
refresh = fmt . Sprintf ( "after %s" , opts . CookieRefresh )
}
2015-03-17 23:13:45 -04:00
2015-06-22 15:10:08 -04:00
log . Printf ( "Cookie settings: name:%s secure(https):%v httponly:%v expiry:%s domain:%s refresh:%s" , opts . CookieName , opts . CookieSecure , opts . CookieHttpOnly , opts . CookieExpire , domain , refresh )
2015-03-17 23:13:45 -04:00
2015-06-23 07:23:39 -04:00
var cipher * cookie . Cipher
2015-05-09 16:08:55 -04:00
if opts . PassAccessToken || ( opts . CookieRefresh != time . Duration ( 0 ) ) {
2015-04-02 20:57:17 -04:00
var err error
2015-06-23 07:23:39 -04:00
cipher , err = cookie . NewCipher ( opts . CookieSecret )
2015-04-02 20:57:17 -04:00
if err != nil {
log . Fatal ( "error creating AES cipher with " +
2015-05-09 17:31:13 -04:00
"cookie-secret " , opts . CookieSecret , ": " , err )
2015-04-02 20:57:17 -04:00
}
}
2014-11-09 14:51:10 -05:00
return & OauthProxy {
2015-06-07 23:52:28 -04:00
CookieName : opts . CookieName ,
2015-03-17 23:13:45 -04:00
CookieSeed : opts . CookieSecret ,
CookieDomain : opts . CookieDomain ,
CookieSecure : opts . CookieSecure ,
CookieHttpOnly : opts . CookieHttpOnly ,
CookieExpire : opts . CookieExpire ,
2015-05-08 10:00:57 -04:00
CookieRefresh : opts . CookieRefresh ,
2015-03-17 23:13:45 -04:00
Validator : validator ,
2014-11-09 14:51:10 -05:00
2015-05-29 15:47:40 -07:00
RobotsPath : "/robots.txt" ,
PingPath : "/ping" ,
SignInPath : fmt . Sprintf ( "%s/sign_in" , opts . ProxyPrefix ) ,
OauthStartPath : fmt . Sprintf ( "%s/start" , opts . ProxyPrefix ) ,
OauthCallbackPath : fmt . Sprintf ( "%s/callback" , opts . ProxyPrefix ) ,
2015-06-06 14:15:43 -04:00
ProxyPrefix : opts . ProxyPrefix ,
provider : opts . provider ,
serveMux : serveMux ,
redirectUrl : redirectUrl ,
skipAuthRegex : opts . SkipAuthRegex ,
compiledRegex : opts . CompiledRegex ,
PassBasicAuth : opts . PassBasicAuth ,
PassAccessToken : opts . PassAccessToken ,
2015-06-23 07:23:39 -04:00
CookieCipher : cipher ,
2015-06-06 14:15:43 -04:00
templates : loadTemplates ( opts . CustomTemplatesDir ) ,
2012-12-10 20:59:23 -05:00
}
}
2015-06-06 14:15:43 -04:00
func ( p * OauthProxy ) GetRedirectURI ( host string ) string {
2015-03-17 16:25:19 -04:00
// default to the request Host if not set
if p . redirectUrl . Host != "" {
return p . redirectUrl . String ( )
}
var u url . URL
u = * p . redirectUrl
if u . Scheme == "" {
2015-03-17 23:13:45 -04:00
if p . CookieSecure {
2015-03-17 16:25:19 -04:00
u . Scheme = "https"
} else {
u . Scheme = "http"
}
}
u . Host = host
return u . String ( )
}
2014-12-09 14:38:57 -06:00
func ( p * OauthProxy ) displayCustomLoginForm ( ) bool {
return p . HtpasswdFile != nil && p . DisplayHtpasswdForm
}
2015-06-23 07:23:39 -04:00
func ( p * OauthProxy ) redeemCode ( host , code string ) ( s * providers . SessionState , err error ) {
2013-10-22 19:56:29 +00:00
if code == "" {
2015-06-23 07:23:39 -04:00
return nil , errors . New ( "missing code" )
2013-10-22 19:56:29 +00:00
}
2015-06-06 14:15:43 -04:00
redirectUri := p . GetRedirectURI ( host )
2015-06-23 07:23:39 -04:00
s , err = p . provider . Redeem ( redirectUri , code )
2012-12-10 20:59:23 -05:00
if err != nil {
2015-06-23 07:23:39 -04:00
return
2012-12-10 20:59:23 -05:00
}
2012-12-17 13:15:23 -05:00
2015-06-23 07:23:39 -04:00
if s . Email == "" {
s . Email , err = p . provider . GetEmailAddress ( s )
2014-08-07 16:16:39 -04:00
}
2015-06-23 07:23:39 -04:00
return
2014-08-07 16:16:39 -04:00
}
2015-06-22 15:10:08 -04:00
func ( p * OauthProxy ) MakeCookie ( req * http . Request , value string , expiration time . Duration , now time . Time ) * http . Cookie {
2015-03-19 15:59:48 -04:00
domain := req . Host
if h , _ , err := net . SplitHostPort ( domain ) ; err == nil {
domain = h
}
if p . CookieDomain != "" {
if ! strings . HasSuffix ( domain , p . CookieDomain ) {
log . Printf ( "Warning: request host is %q but using configured cookie domain of %q" , domain , p . CookieDomain )
}
2014-11-09 14:51:10 -05:00
domain = p . CookieDomain
2012-12-10 20:59:23 -05:00
}
2015-05-08 11:51:11 -04:00
if value != "" {
2015-06-23 07:23:39 -04:00
value = cookie . SignedValue ( p . CookieSeed , p . CookieName , value , now )
2015-05-08 11:51:11 -04:00
}
return & http . Cookie {
2015-06-07 23:52:28 -04:00
Name : p . CookieName ,
2015-05-08 11:51:11 -04:00
Value : value ,
2012-12-10 20:59:23 -05:00
Path : "/" ,
Domain : domain ,
2015-01-19 15:52:18 +00:00
HttpOnly : p . CookieHttpOnly ,
2015-03-19 15:59:48 -04:00
Secure : p . CookieSecure ,
2015-06-22 15:10:08 -04:00
Expires : now . Add ( expiration ) ,
2012-12-10 20:59:23 -05:00
}
}
2015-05-08 11:51:11 -04:00
func ( p * OauthProxy ) ClearCookie ( rw http . ResponseWriter , req * http . Request ) {
2015-06-22 15:10:08 -04:00
http . SetCookie ( rw , p . MakeCookie ( req , "" , time . Hour * - 1 , time . Now ( ) ) )
2012-12-10 20:59:23 -05:00
}
2012-12-26 10:35:02 -05:00
func ( p * OauthProxy ) SetCookie ( rw http . ResponseWriter , req * http . Request , val string ) {
2015-06-22 15:10:08 -04:00
http . SetCookie ( rw , p . MakeCookie ( req , val , p . CookieExpire , time . Now ( ) ) )
2012-12-26 10:35:02 -05:00
}
2012-12-26 15:55:41 +00:00
2015-06-23 07:23:39 -04:00
func ( p * OauthProxy ) LoadCookiedSession ( req * http . Request ) ( * providers . SessionState , time . Duration , error ) {
var age time . Duration
c , err := req . Cookie ( p . CookieName )
if err != nil {
// always http.ErrNoCookie
return nil , age , fmt . Errorf ( "Cookie %q not present" , p . CookieName )
}
val , timestamp , ok := cookie . Validate ( c , p . CookieSeed , p . CookieExpire )
if ! ok {
return nil , age , errors . New ( "Cookie Signature not valid" )
2012-12-26 10:35:02 -05:00
}
2015-06-23 07:23:39 -04:00
session , err := p . provider . SessionFromCookie ( val , p . CookieCipher )
2015-05-08 11:51:43 -04:00
if err != nil {
2015-06-23 07:23:39 -04:00
return nil , age , err
2012-12-26 10:35:02 -05:00
}
2015-06-23 07:23:39 -04:00
age = time . Now ( ) . Truncate ( time . Second ) . Sub ( timestamp )
return session , age , nil
}
func ( p * OauthProxy ) SaveSession ( rw http . ResponseWriter , req * http . Request , s * providers . SessionState ) error {
value , err := p . provider . CookieForSession ( s , p . CookieCipher )
if err != nil {
return err
}
p . SetCookie ( rw , req , value )
return nil
2012-12-26 10:35:02 -05:00
}
2015-05-10 15:15:52 -04:00
func ( p * OauthProxy ) RobotsTxt ( rw http . ResponseWriter ) {
rw . WriteHeader ( http . StatusOK )
fmt . Fprintf ( rw , "User-agent: *\nDisallow: /" )
}
2014-10-14 16:22:38 -04:00
func ( p * OauthProxy ) PingPage ( rw http . ResponseWriter ) {
rw . WriteHeader ( http . StatusOK )
2014-10-14 17:05:59 -04:00
fmt . Fprintf ( rw , "OK" )
2014-10-14 16:22:38 -04:00
}
2012-12-17 13:15:23 -05:00
func ( p * OauthProxy ) ErrorPage ( rw http . ResponseWriter , code int , title string , message string ) {
log . Printf ( "ErrorPage %d %s %s" , code , title , message )
2012-12-10 20:59:23 -05:00
rw . WriteHeader ( code )
2012-12-17 13:15:23 -05:00
t := struct {
2012-12-17 13:38:33 -05:00
Title string
Message string
2012-12-10 20:59:23 -05:00
} {
2012-12-17 13:38:33 -05:00
Title : fmt . Sprintf ( "%d %s" , code , title ) ,
Message : message ,
2012-12-10 20:59:23 -05:00
}
2015-03-17 18:06:06 -04:00
p . templates . ExecuteTemplate ( rw , "error.html" , t )
2012-12-17 13:15:23 -05:00
}
func ( p * OauthProxy ) SignInPage ( rw http . ResponseWriter , req * http . Request , code int ) {
2012-12-26 10:35:02 -05:00
p . ClearCookie ( rw , req )
2012-12-17 13:15:23 -05:00
rw . WriteHeader ( code )
2012-12-26 10:35:02 -05:00
2015-04-06 22:10:03 -04:00
redirect_url := req . URL . RequestURI ( )
2015-05-29 15:47:40 -07:00
if redirect_url == p . SignInPath {
2015-04-06 22:10:03 -04:00
redirect_url = "/"
}
2012-12-26 10:35:02 -05:00
t := struct {
2015-03-31 12:59:07 -04:00
ProviderName string
2012-12-26 15:55:41 +00:00
SignInMessage string
2014-12-09 14:38:57 -06:00
CustomLogin bool
2013-10-22 19:56:29 +00:00
Redirect string
2014-11-09 22:01:50 -05:00
Version string
2015-05-29 15:47:40 -07:00
ProxyPrefix string
2012-12-26 15:55:41 +00:00
} {
2015-03-31 12:59:07 -04:00
ProviderName : p . provider . Data ( ) . ProviderName ,
2012-12-26 10:35:02 -05:00
SignInMessage : p . SignInMessage ,
2014-12-09 14:38:57 -06:00
CustomLogin : p . displayCustomLoginForm ( ) ,
2015-04-06 22:10:03 -04:00
Redirect : redirect_url ,
2014-11-09 22:01:50 -05:00
Version : VERSION ,
2015-05-29 15:47:40 -07:00
ProxyPrefix : p . ProxyPrefix ,
2012-12-26 15:55:41 +00:00
}
2015-03-17 18:06:06 -04:00
p . templates . ExecuteTemplate ( rw , "sign_in.html" , t )
2012-12-10 20:59:23 -05:00
}
2012-12-26 10:35:02 -05:00
func ( p * OauthProxy ) ManualSignIn ( rw http . ResponseWriter , req * http . Request ) ( string , bool ) {
if req . Method != "POST" || p . HtpasswdFile == nil {
2012-12-26 15:55:41 +00:00
return "" , false
}
user := req . FormValue ( "username" )
passwd := req . FormValue ( "password" )
if user == "" {
return "" , false
}
// check auth
if p . HtpasswdFile . Validate ( user , passwd ) {
2015-03-19 16:37:16 -04:00
log . Printf ( "authenticated %q via HtpasswdFile" , user )
2012-12-26 15:55:41 +00:00
return user , true
}
return "" , false
}
2013-10-24 15:31:08 +00:00
func ( p * OauthProxy ) GetRedirect ( req * http . Request ) ( string , error ) {
err := req . ParseForm ( )
if err != nil {
return "" , err
}
redirect := req . FormValue ( "rd" )
if redirect == "" {
redirect = "/"
}
return redirect , err
}
2015-06-23 07:23:39 -04:00
func ( p * OauthProxy ) IsWhitelistedPath ( path string ) ( ok bool ) {
for _ , u := range p . compiledRegex {
ok = u . MatchString ( path )
if ok {
return
}
2012-12-26 15:55:41 +00:00
}
2015-06-23 07:23:39 -04:00
return
}
2012-12-26 10:35:02 -05:00
2015-06-23 07:23:39 -04:00
func getRemoteAddr ( req * http . Request ) ( s string ) {
s = req . RemoteAddr
if req . Header . Get ( "X-Real-IP" ) != "" {
s += fmt . Sprintf ( " (%q)" , req . Header . Get ( "X-Real-IP" ) )
}
return
}
2013-10-22 19:56:29 +00:00
2015-06-23 07:23:39 -04:00
func ( p * OauthProxy ) ServeHTTP ( rw http . ResponseWriter , req * http . Request ) {
switch path := req . URL . Path ; {
case path == p . RobotsPath :
2015-05-10 15:15:52 -04:00
p . RobotsTxt ( rw )
2015-06-23 07:23:39 -04:00
case path == p . PingPath :
p . PingPage ( rw )
case p . IsWhitelistedPath ( path ) :
p . serveMux . ServeHTTP ( rw , req )
case path == p . SignInPath :
p . SignIn ( rw , req )
case path == p . OauthStartPath :
p . OauthStart ( rw , req )
case path == p . OauthCallbackPath :
p . OauthCallback ( rw , req )
default :
p . Proxy ( rw , req )
2015-05-10 15:15:52 -04:00
}
2015-06-23 07:23:39 -04:00
}
2015-05-10 15:15:52 -04:00
2015-06-23 07:23:39 -04:00
func ( p * OauthProxy ) SignIn ( rw http . ResponseWriter , req * http . Request ) {
redirect , err := p . GetRedirect ( req )
if err != nil {
p . ErrorPage ( rw , 500 , "Internal Error" , err . Error ( ) )
2014-10-14 16:22:38 -04:00
return
}
2015-06-23 07:23:39 -04:00
user , ok := p . ManualSignIn ( rw , req )
if ok {
session := & providers . SessionState { User : user }
p . SaveSession ( rw , req , session )
http . Redirect ( rw , req , redirect , 302 )
} else {
p . SignInPage ( rw , req , 200 )
}
}
2015-01-12 14:48:41 +05:30
2015-06-23 07:23:39 -04:00
func ( p * OauthProxy ) OauthStart ( rw http . ResponseWriter , req * http . Request ) {
redirect , err := p . GetRedirect ( req )
if err != nil {
p . ErrorPage ( rw , 500 , "Internal Error" , err . Error ( ) )
return
2015-01-12 14:48:41 +05:30
}
2015-06-23 07:23:39 -04:00
redirectURI := p . GetRedirectURI ( req . Host )
http . Redirect ( rw , req , p . provider . GetLoginURL ( redirectURI , redirect ) , 302 )
}
2015-01-12 14:48:41 +05:30
2015-06-23 07:23:39 -04:00
func ( p * OauthProxy ) OauthCallback ( rw http . ResponseWriter , req * http . Request ) {
remoteAddr := getRemoteAddr ( req )
2013-10-24 15:31:08 +00:00
2015-06-23 07:23:39 -04:00
// finish the oauth cycle
err := req . ParseForm ( )
if err != nil {
p . ErrorPage ( rw , 500 , "Internal Error" , err . Error ( ) )
2012-12-10 20:59:23 -05:00
return
}
2015-06-23 07:23:39 -04:00
errorString := req . Form . Get ( "error" )
if errorString != "" {
p . ErrorPage ( rw , 403 , "Permission Denied" , errorString )
2012-12-10 20:59:23 -05:00
return
}
2015-06-23 07:23:39 -04:00
session , err := p . redeemCode ( req . Host , req . Form . Get ( "code" ) )
if err != nil {
log . Printf ( "%s error redeeming code %s" , remoteAddr , err )
p . ErrorPage ( rw , 500 , "Internal Error" , "Internal Error" )
return
}
redirect := req . Form . Get ( "state" )
if redirect == "" {
redirect = "/"
}
// set cookie, or deny
if p . Validator ( session . Email ) {
log . Printf ( "%s authentication complete %s" , remoteAddr , session )
err := p . SaveSession ( rw , req , session )
2012-12-10 20:59:23 -05:00
if err != nil {
2015-06-23 07:23:39 -04:00
log . Printf ( "%s %s" , remoteAddr , err )
p . ErrorPage ( rw , 500 , "Internal Error" , "Internal Error" )
2012-12-10 20:59:23 -05:00
return
}
2015-06-23 07:23:39 -04:00
http . Redirect ( rw , req , redirect , 302 )
} else {
log . Printf ( "%s Permission Denied: %q is unauthorized" , remoteAddr , session . Email )
p . ErrorPage ( rw , 403 , "Permission Denied" , "Invalid Account" )
}
}
2012-12-10 20:59:23 -05:00
2015-06-23 07:23:39 -04:00
func ( p * OauthProxy ) Proxy ( rw http . ResponseWriter , req * http . Request ) {
var saveSession , clearSession , revalidated bool
remoteAddr := getRemoteAddr ( req )
session , sessionAge , err := p . LoadCookiedSession ( req )
if err != nil {
log . Printf ( "%s %s" , remoteAddr , err )
}
if session != nil && sessionAge > p . CookieRefresh && p . CookieRefresh != time . Duration ( 0 ) {
log . Printf ( "%s refreshing %s old session cookie for %s (refresh after %s)" , remoteAddr , sessionAge , session , p . CookieRefresh )
saveSession = true
}
if ok , err := p . provider . RefreshSessionIfNeeded ( session ) ; err != nil {
log . Printf ( "%s removing session. error refreshing access token %s %s" , remoteAddr , err , session )
clearSession = true
session = nil
} else if ok {
saveSession = true
revalidated = true
}
if session != nil && session . IsExpired ( ) {
log . Printf ( "%s removing session. token expired %s" , remoteAddr , session )
session = nil
saveSession = false
clearSession = true
}
if saveSession && ! revalidated && session . AccessToken != "" {
if ! p . provider . ValidateSessionState ( session ) {
log . Printf ( "%s removing session. error validating %s" , remoteAddr , session )
saveSession = false
session = nil
clearSession = true
2013-10-22 19:56:29 +00:00
}
2015-06-23 07:23:39 -04:00
}
2013-10-22 19:56:29 +00:00
2015-06-23 07:23:39 -04:00
if saveSession && session . Email != "" && ! p . Validator ( session . Email ) {
log . Printf ( "%s Permission Denied: removing session %s" , remoteAddr , session )
session = nil
saveSession = false
clearSession = true
}
if saveSession {
err := p . SaveSession ( rw , req , session )
if err != nil {
log . Printf ( "%s %s" , remoteAddr , err )
p . ErrorPage ( rw , 500 , "Internal Error" , "Internal Error" )
2012-12-10 20:59:23 -05:00
return
}
}
2012-12-17 13:38:33 -05:00
2015-06-23 07:23:39 -04:00
if clearSession {
p . ClearCookie ( rw , req )
2012-12-10 20:59:23 -05:00
}
2015-06-23 07:23:39 -04:00
if session == nil {
session , err = p . CheckBasicAuth ( req )
if err != nil {
log . Printf ( "%s %s" , remoteAddr , err )
}
2012-12-10 20:59:23 -05:00
}
2015-06-23 07:23:39 -04:00
if session == nil {
2012-12-17 13:15:23 -05:00
p . SignInPage ( rw , req , 403 )
2012-12-10 20:59:23 -05:00
return
}
// At this point, the user is authenticated. proxy normally
2014-11-09 14:51:10 -05:00
if p . PassBasicAuth {
2015-06-23 07:23:39 -04:00
req . SetBasicAuth ( session . User , "" )
req . Header [ "X-Forwarded-User" ] = [ ] string { session . User }
if session . Email != "" {
req . Header [ "X-Forwarded-Email" ] = [ ] string { session . Email }
}
2012-12-10 20:59:23 -05:00
}
2015-06-23 07:23:39 -04:00
if p . PassAccessToken && session . AccessToken != "" {
req . Header [ "X-Forwarded-Access-Token" ] = [ ] string { session . AccessToken }
2015-04-02 20:57:17 -04:00
}
2015-06-23 07:23:39 -04:00
if session . Email == "" {
rw . Header ( ) . Set ( "GAP-Auth" , session . User )
2015-03-19 16:37:16 -04:00
} else {
2015-06-23 07:23:39 -04:00
rw . Header ( ) . Set ( "GAP-Auth" , session . Email )
2015-03-19 16:37:16 -04:00
}
2012-12-10 20:59:23 -05:00
p . serveMux . ServeHTTP ( rw , req )
}
2015-06-23 07:23:39 -04:00
func ( p * OauthProxy ) CheckBasicAuth ( req * http . Request ) ( * providers . SessionState , error ) {
2012-12-10 20:59:23 -05:00
if p . HtpasswdFile == nil {
2015-06-23 07:23:39 -04:00
return nil , nil
}
auth := req . Header . Get ( "Authorization" )
if auth == "" {
return nil , nil
2012-12-10 20:59:23 -05:00
}
2015-06-23 07:23:39 -04:00
s := strings . SplitN ( auth , " " , 2 )
2012-12-10 20:59:23 -05:00
if len ( s ) != 2 || s [ 0 ] != "Basic" {
2015-06-23 07:23:39 -04:00
return nil , fmt . Errorf ( "invalid Authorization header %s" , req . Header . Get ( "Authorization" ) )
2012-12-10 20:59:23 -05:00
}
b , err := base64 . StdEncoding . DecodeString ( s [ 1 ] )
if err != nil {
2015-06-23 07:23:39 -04:00
return nil , err
2012-12-10 20:59:23 -05:00
}
pair := strings . SplitN ( string ( b ) , ":" , 2 )
if len ( pair ) != 2 {
2015-06-23 07:23:39 -04:00
return nil , fmt . Errorf ( "invalid format %s" , b )
2012-12-10 20:59:23 -05:00
}
if p . HtpasswdFile . Validate ( pair [ 0 ] , pair [ 1 ] ) {
2015-03-19 16:37:16 -04:00
log . Printf ( "authenticated %q via basic auth" , pair [ 0 ] )
2015-06-23 07:23:39 -04:00
return & providers . SessionState { User : pair [ 0 ] } , nil
2012-12-10 20:59:23 -05:00
}
2015-06-23 07:23:39 -04:00
return nil , fmt . Errorf ( "%s not in HtpasswdFile" , pair [ 0 ] )
2012-12-10 20:59:23 -05:00
}