2014-12-01 04:12:33 +03:00
package main
import (
2015-11-16 06:08:30 +03:00
"crypto"
2015-07-24 12:17:43 +03:00
"encoding/base64"
2015-11-16 06:08:30 +03:00
"io"
2014-12-01 04:12:33 +03:00
"io/ioutil"
"net"
"net/http"
"net/http/httptest"
"net/url"
2015-04-07 05:10:03 +03:00
"regexp"
2015-04-03 03:57:17 +03:00
"strings"
2014-12-01 04:12:33 +03:00
"testing"
2015-04-03 03:57:17 +03:00
"time"
2017-06-22 01:02:34 +03:00
2017-09-13 01:59:00 +03:00
"github.com/mbland/hmacauth"
2019-02-10 19:37:45 +03:00
"github.com/pusher/oauth2_proxy/logger"
2018-11-29 17:26:41 +03:00
"github.com/pusher/oauth2_proxy/providers"
2017-10-23 19:23:46 +03:00
"github.com/stretchr/testify/assert"
2019-01-29 15:13:02 +03:00
"github.com/stretchr/testify/require"
2019-03-08 11:15:21 +03:00
"golang.org/x/net/websocket"
2014-12-01 04:12:33 +03:00
)
2015-05-21 06:23:48 +03:00
func init ( ) {
2019-02-10 19:37:45 +03:00
logger . SetFlags ( logger . Lshortfile )
2015-05-21 06:23:48 +03:00
}
2019-03-08 11:15:21 +03:00
type WebSocketOrRestHandler struct {
restHandler http . Handler
wsHandler http . Handler
}
func ( h * WebSocketOrRestHandler ) ServeHTTP ( w http . ResponseWriter , r * http . Request ) {
if r . Header . Get ( "Upgrade" ) == "websocket" {
h . wsHandler . ServeHTTP ( w , r )
} else {
h . restHandler . ServeHTTP ( w , r )
}
}
func TestWebSocketProxy ( t * testing . T ) {
handler := WebSocketOrRestHandler {
restHandler : http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
w . WriteHeader ( 200 )
hostname , _ , _ := net . SplitHostPort ( r . Host )
w . Write ( [ ] byte ( hostname ) )
} ) ,
wsHandler : websocket . Handler ( func ( ws * websocket . Conn ) {
defer ws . Close ( )
var data [ ] byte
err := websocket . Message . Receive ( ws , & data )
if err != nil {
t . Fatalf ( "err %s" , err )
return
}
err = websocket . Message . Send ( ws , data )
if err != nil {
t . Fatalf ( "err %s" , err )
}
return
} ) ,
}
backend := httptest . NewServer ( & handler )
defer backend . Close ( )
backendURL , _ := url . Parse ( backend . URL )
options := NewOptions ( )
var auth hmacauth . HmacAuth
options . PassHostHeader = true
proxyHandler := NewWebSocketOrRestReverseProxy ( backendURL , options , auth )
frontend := httptest . NewServer ( proxyHandler )
defer frontend . Close ( )
frontendURL , _ := url . Parse ( frontend . URL )
frontendWSURL := "ws://" + frontendURL . Host + "/"
ws , err := websocket . Dial ( frontendWSURL , "" , "http://localhost/" )
if err != nil {
t . Fatalf ( "err %s" , err )
}
request := [ ] byte ( "hello, world!" )
err = websocket . Message . Send ( ws , request )
if err != nil {
t . Fatalf ( "err %s" , err )
}
var response = make ( [ ] byte , 1024 )
websocket . Message . Receive ( ws , & response )
if err != nil {
t . Fatalf ( "err %s" , err )
}
if g , e := string ( request ) , string ( response ) ; g != e {
t . Errorf ( "got body %q; expected %q" , g , e )
}
getReq , _ := http . NewRequest ( "GET" , frontend . URL , nil )
res , _ := http . DefaultClient . Do ( getReq )
bodyBytes , _ := ioutil . ReadAll ( res . Body )
backendHostname , _ , _ := net . SplitHostPort ( backendURL . Host )
if g , e := string ( bodyBytes ) , backendHostname ; g != e {
t . Errorf ( "got body %q; expected %q" , g , e )
}
}
2014-12-01 04:12:33 +03:00
func TestNewReverseProxy ( t * testing . T ) {
backend := httptest . NewServer ( http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
w . WriteHeader ( 200 )
2015-03-17 22:15:15 +03:00
hostname , _ , _ := net . SplitHostPort ( r . Host )
2014-12-01 04:12:33 +03:00
w . Write ( [ ] byte ( hostname ) )
} ) )
defer backend . Close ( )
backendURL , _ := url . Parse ( backend . URL )
2015-04-03 04:06:37 +03:00
backendHostname , backendPort , _ := net . SplitHostPort ( backendURL . Host )
2014-12-01 04:12:33 +03:00
backendHost := net . JoinHostPort ( backendHostname , backendPort )
proxyURL , _ := url . Parse ( backendURL . Scheme + "://" + backendHost + "/" )
2019-01-31 17:02:15 +03:00
proxyHandler := NewReverseProxy ( proxyURL , time . Second )
2015-03-17 22:15:15 +03:00
setProxyUpstreamHostHeader ( proxyHandler , proxyURL )
2014-12-01 04:12:33 +03:00
frontend := httptest . NewServer ( proxyHandler )
defer frontend . Close ( )
getReq , _ := http . NewRequest ( "GET" , frontend . URL , nil )
res , _ := http . DefaultClient . Do ( getReq )
bodyBytes , _ := ioutil . ReadAll ( res . Body )
if g , e := string ( bodyBytes ) , backendHostname ; g != e {
t . Errorf ( "got body %q; expected %q" , g , e )
}
}
2015-03-18 00:17:40 +03:00
func TestEncodedSlashes ( t * testing . T ) {
var seen string
backend := httptest . NewServer ( http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
w . WriteHeader ( 200 )
seen = r . RequestURI
} ) )
defer backend . Close ( )
b , _ := url . Parse ( backend . URL )
2019-01-31 17:02:15 +03:00
proxyHandler := NewReverseProxy ( b , time . Second )
2015-03-18 00:17:40 +03:00
setProxyDirector ( proxyHandler )
frontend := httptest . NewServer ( proxyHandler )
defer frontend . Close ( )
f , _ := url . Parse ( frontend . URL )
2015-03-21 22:29:07 +03:00
encodedPath := "/a%2Fb/?c=1"
2015-03-18 00:17:40 +03:00
getReq := & http . Request { URL : & url . URL { Scheme : "http" , Host : f . Host , Opaque : encodedPath } }
_ , err := http . DefaultClient . Do ( getReq )
if err != nil {
t . Fatalf ( "err %s" , err )
}
2015-03-21 22:29:07 +03:00
if seen != encodedPath {
t . Errorf ( "got bad request %q expected %q" , seen , encodedPath )
2015-03-18 00:17:40 +03:00
}
}
2015-04-03 03:57:17 +03:00
2015-05-10 22:15:52 +03:00
func TestRobotsTxt ( t * testing . T ) {
opts := NewOptions ( )
opts . ClientID = "bazquux"
opts . ClientSecret = "foobar"
opts . CookieSecret = "xyzzyplugh"
opts . Validate ( )
2015-11-09 02:57:01 +03:00
proxy := NewOAuthProxy ( opts , func ( string ) bool { return true } )
2015-05-10 22:15:52 +03:00
rw := httptest . NewRecorder ( )
req , _ := http . NewRequest ( "GET" , "/robots.txt" , nil )
proxy . ServeHTTP ( rw , req )
assert . Equal ( t , 200 , rw . Code )
assert . Equal ( t , "User-agent: *\nDisallow: /" , rw . Body . String ( ) )
}
2017-10-02 12:19:24 +03:00
func TestIsValidRedirect ( t * testing . T ) {
opts := NewOptions ( )
opts . ClientID = "bazquux"
opts . ClientSecret = "foobar"
opts . CookieSecret = "xyzzyplugh"
2017-12-11 12:33:52 +03:00
// Should match domains that are exactly foo.bar and any subdomain of bar.foo
opts . WhitelistDomains = [ ] string { "foo.bar" , ".bar.foo" }
2017-10-02 12:19:24 +03:00
opts . Validate ( )
proxy := NewOAuthProxy ( opts , func ( string ) bool { return true } )
noRD := proxy . IsValidRedirect ( "" )
assert . Equal ( t , false , noRD )
singleSlash := proxy . IsValidRedirect ( "/redirect" )
assert . Equal ( t , true , singleSlash )
doubleSlash := proxy . IsValidRedirect ( "//redirect" )
assert . Equal ( t , false , doubleSlash )
2017-12-11 12:33:52 +03:00
validHTTP := proxy . IsValidRedirect ( "http://foo.bar/redirect" )
2017-10-02 12:19:24 +03:00
assert . Equal ( t , true , validHTTP )
2017-12-11 12:33:52 +03:00
validHTTPS := proxy . IsValidRedirect ( "https://foo.bar/redirect" )
2017-10-02 12:19:24 +03:00
assert . Equal ( t , true , validHTTPS )
2017-12-11 12:33:52 +03:00
invalidHTTPSubdomain := proxy . IsValidRedirect ( "http://baz.foo.bar/redirect" )
assert . Equal ( t , false , invalidHTTPSubdomain )
invalidHTTPSSubdomain := proxy . IsValidRedirect ( "https://baz.foo.bar/redirect" )
assert . Equal ( t , false , invalidHTTPSSubdomain )
validHTTPSubdomain := proxy . IsValidRedirect ( "http://baz.bar.foo/redirect" )
assert . Equal ( t , true , validHTTPSubdomain )
validHTTPSSubdomain := proxy . IsValidRedirect ( "https://baz.bar.foo/redirect" )
assert . Equal ( t , true , validHTTPSSubdomain )
2017-10-02 12:19:24 +03:00
invalidHTTP1 := proxy . IsValidRedirect ( "http://foo.bar.evil.corp/redirect" )
assert . Equal ( t , false , invalidHTTP1 )
invalidHTTPS1 := proxy . IsValidRedirect ( "https://foo.bar.evil.corp/redirect" )
assert . Equal ( t , false , invalidHTTPS1 )
invalidHTTP2 := proxy . IsValidRedirect ( "http://evil.corp/redirect?rd=foo.bar" )
assert . Equal ( t , false , invalidHTTP2 )
invalidHTTPS2 := proxy . IsValidRedirect ( "https://evil.corp/redirect?rd=foo.bar" )
assert . Equal ( t , false , invalidHTTPS2 )
}
2015-11-16 06:08:30 +03:00
type TestProvider struct {
* providers . ProviderData
EmailAddress string
ValidToken bool
}
2018-11-29 17:26:41 +03:00
func NewTestProvider ( providerURL * url . URL , emailAddress string ) * TestProvider {
2015-11-16 06:08:30 +03:00
return & TestProvider {
ProviderData : & providers . ProviderData {
ProviderName : "Test Provider" ,
LoginURL : & url . URL {
Scheme : "http" ,
2018-11-29 17:26:41 +03:00
Host : providerURL . Host ,
2015-11-16 06:08:30 +03:00
Path : "/oauth/authorize" ,
} ,
RedeemURL : & url . URL {
Scheme : "http" ,
2018-11-29 17:26:41 +03:00
Host : providerURL . Host ,
2015-11-16 06:08:30 +03:00
Path : "/oauth/token" ,
} ,
ProfileURL : & url . URL {
Scheme : "http" ,
2018-11-29 17:26:41 +03:00
Host : providerURL . Host ,
2015-11-16 06:08:30 +03:00
Path : "/api/v1/profile" ,
} ,
Scope : "profile.email" ,
} ,
2018-11-29 17:26:41 +03:00
EmailAddress : emailAddress ,
2015-11-16 06:08:30 +03:00
}
}
func ( tp * TestProvider ) GetEmailAddress ( session * providers . SessionState ) ( string , error ) {
return tp . EmailAddress , nil
}
func ( tp * TestProvider ) ValidateSessionState ( session * providers . SessionState ) bool {
return tp . ValidToken
}
2015-07-24 12:17:43 +03:00
func TestBasicAuthPassword ( t * testing . T ) {
2018-11-29 17:26:41 +03:00
providerServer := httptest . NewServer ( http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
2019-02-10 19:37:45 +03:00
logger . Printf ( "%#v" , r )
2018-11-29 17:26:41 +03:00
var payload string
switch r . URL . Path {
2015-07-24 12:17:43 +03:00
case "/oauth/token" :
payload = ` { "access_token": "my_auth_token"} `
default :
payload = r . Header . Get ( "Authorization" )
if payload == "" {
payload = "No Authorization header found."
}
}
w . WriteHeader ( 200 )
w . Write ( [ ] byte ( payload ) )
} ) )
opts := NewOptions ( )
2018-11-29 17:26:41 +03:00
opts . Upstreams = append ( opts . Upstreams , providerServer . URL )
2015-07-24 12:17:43 +03:00
// The CookieSecret must be 32 bytes in order to create the AES
// cipher.
opts . CookieSecret = "xyzzyplughxyzzyplughxyzzyplughxp"
opts . ClientID = "bazquux"
opts . ClientSecret = "foobar"
opts . CookieSecure = false
opts . PassBasicAuth = true
2016-02-08 18:57:47 +03:00
opts . PassUserHeaders = true
2015-07-24 12:17:43 +03:00
opts . BasicAuthPassword = "This is a secure password"
opts . Validate ( )
2018-11-29 17:26:41 +03:00
providerURL , _ := url . Parse ( providerServer . URL )
const emailAddress = "michael.bland@gsa.gov"
const username = "michael.bland"
2015-07-24 12:17:43 +03:00
2018-11-29 17:26:41 +03:00
opts . provider = NewTestProvider ( providerURL , emailAddress )
2015-11-09 02:57:01 +03:00
proxy := NewOAuthProxy ( opts , func ( email string ) bool {
2018-11-29 17:26:41 +03:00
return email == emailAddress
2015-07-24 12:17:43 +03:00
} )
rw := httptest . NewRecorder ( )
2017-03-28 04:14:38 +03:00
req , _ := http . NewRequest ( "GET" , "/oauth2/callback?code=callback_code&state=nonce:" ,
2015-07-24 12:17:43 +03:00
strings . NewReader ( "" ) )
2017-03-28 04:14:38 +03:00
req . AddCookie ( proxy . MakeCSRFCookie ( req , "nonce" , proxy . CookieExpire , time . Now ( ) ) )
2015-07-24 12:17:43 +03:00
proxy . ServeHTTP ( rw , req )
2017-03-28 04:14:38 +03:00
if rw . Code >= 400 {
t . Fatalf ( "expected 3xx got %d" , rw . Code )
}
cookie := rw . HeaderMap [ "Set-Cookie" ] [ 1 ]
2015-07-24 12:17:43 +03:00
cookieName := proxy . CookieName
var value string
2018-11-29 17:26:41 +03:00
keyPrefix := cookieName + "="
2015-07-24 12:17:43 +03:00
for _ , field := range strings . Split ( cookie , "; " ) {
2018-11-29 17:26:41 +03:00
value = strings . TrimPrefix ( field , keyPrefix )
2015-07-24 12:17:43 +03:00
if value != field {
break
} else {
value = ""
}
}
req , _ = http . NewRequest ( "GET" , "/" , strings . NewReader ( "" ) )
req . AddCookie ( & http . Cookie {
Name : cookieName ,
Value : value ,
Path : "/" ,
Expires : time . Now ( ) . Add ( time . Duration ( 24 ) ) ,
HttpOnly : true ,
} )
2017-03-28 04:14:38 +03:00
req . AddCookie ( proxy . MakeCSRFCookie ( req , "nonce" , proxy . CookieExpire , time . Now ( ) ) )
2015-07-24 12:17:43 +03:00
rw = httptest . NewRecorder ( )
proxy . ServeHTTP ( rw , req )
2017-03-28 04:14:38 +03:00
2018-11-29 17:26:41 +03:00
expectedHeader := "Basic " + base64 . StdEncoding . EncodeToString ( [ ] byte ( username + ":" + opts . BasicAuthPassword ) )
2015-07-24 12:17:43 +03:00
assert . Equal ( t , expectedHeader , rw . Body . String ( ) )
2018-11-29 17:26:41 +03:00
providerServer . Close ( )
2015-07-24 12:17:43 +03:00
}
2015-04-03 03:57:17 +03:00
type PassAccessTokenTest struct {
2018-11-29 17:26:41 +03:00
providerServer * httptest . Server
proxy * OAuthProxy
opts * Options
2015-04-03 03:57:17 +03:00
}
type PassAccessTokenTestOptions struct {
PassAccessToken bool
}
func NewPassAccessTokenTest ( opts PassAccessTokenTestOptions ) * PassAccessTokenTest {
t := & PassAccessTokenTest { }
2018-11-29 17:26:41 +03:00
t . providerServer = httptest . NewServer (
2015-04-03 03:57:17 +03:00
http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
2019-02-10 19:37:45 +03:00
logger . Printf ( "%#v" , r )
2018-11-29 17:26:41 +03:00
var payload string
switch r . URL . Path {
2015-04-03 03:57:17 +03:00
case "/oauth/token" :
payload = ` { "access_token": "my_auth_token"} `
default :
2015-05-21 06:23:48 +03:00
payload = r . Header . Get ( "X-Forwarded-Access-Token" )
if payload == "" {
2015-04-03 03:57:17 +03:00
payload = "No access token found."
}
}
w . WriteHeader ( 200 )
w . Write ( [ ] byte ( payload ) )
} ) )
t . opts = NewOptions ( )
2018-11-29 17:26:41 +03:00
t . opts . Upstreams = append ( t . opts . Upstreams , t . providerServer . URL )
2015-04-03 03:57:17 +03:00
// The CookieSecret must be 32 bytes in order to create the AES
// cipher.
t . opts . CookieSecret = "xyzzyplughxyzzyplughxyzzyplughxp"
t . opts . ClientID = "bazquux"
t . opts . ClientSecret = "foobar"
t . opts . CookieSecure = false
t . opts . PassAccessToken = opts . PassAccessToken
t . opts . Validate ( )
2018-11-29 17:26:41 +03:00
providerURL , _ := url . Parse ( t . providerServer . URL )
const emailAddress = "michael.bland@gsa.gov"
2015-04-03 03:57:17 +03:00
2018-11-29 17:26:41 +03:00
t . opts . provider = NewTestProvider ( providerURL , emailAddress )
2015-11-09 02:57:01 +03:00
t . proxy = NewOAuthProxy ( t . opts , func ( email string ) bool {
2018-11-29 17:26:41 +03:00
return email == emailAddress
2015-04-03 03:57:17 +03:00
} )
return t
}
2018-11-29 17:26:41 +03:00
func ( patTest * PassAccessTokenTest ) Close ( ) {
patTest . providerServer . Close ( )
2015-04-03 03:57:17 +03:00
}
2018-11-29 17:26:41 +03:00
func ( patTest * PassAccessTokenTest ) getCallbackEndpoint ( ) ( httpCode int ,
2015-04-07 04:35:58 +03:00
cookie string ) {
2015-04-03 03:57:17 +03:00
rw := httptest . NewRecorder ( )
2017-03-28 04:14:38 +03:00
req , err := http . NewRequest ( "GET" , "/oauth2/callback?code=callback_code&state=nonce:" ,
2015-04-03 03:57:17 +03:00
strings . NewReader ( "" ) )
if err != nil {
return 0 , ""
}
2018-11-29 17:26:41 +03:00
req . AddCookie ( patTest . proxy . MakeCSRFCookie ( req , "nonce" , time . Hour , time . Now ( ) ) )
patTest . proxy . ServeHTTP ( rw , req )
2017-03-28 04:14:38 +03:00
return rw . Code , rw . HeaderMap [ "Set-Cookie" ] [ 1 ]
2015-04-03 03:57:17 +03:00
}
2018-11-29 17:26:41 +03:00
func ( patTest * PassAccessTokenTest ) getRootEndpoint ( cookie string ) ( httpCode int , accessToken string ) {
cookieName := patTest . proxy . CookieName
2015-04-03 03:57:17 +03:00
var value string
2018-11-29 17:26:41 +03:00
keyPrefix := cookieName + "="
2015-04-03 03:57:17 +03:00
for _ , field := range strings . Split ( cookie , "; " ) {
2018-11-29 17:26:41 +03:00
value = strings . TrimPrefix ( field , keyPrefix )
2015-04-03 03:57:17 +03:00
if value != field {
break
} else {
value = ""
}
}
if value == "" {
return 0 , ""
}
req , err := http . NewRequest ( "GET" , "/" , strings . NewReader ( "" ) )
if err != nil {
return 0 , ""
}
req . AddCookie ( & http . Cookie {
2015-06-08 06:52:28 +03:00
Name : cookieName ,
2015-04-03 03:57:17 +03:00
Value : value ,
Path : "/" ,
Expires : time . Now ( ) . Add ( time . Duration ( 24 ) ) ,
HttpOnly : true ,
} )
rw := httptest . NewRecorder ( )
2018-11-29 17:26:41 +03:00
patTest . proxy . ServeHTTP ( rw , req )
2015-04-03 03:57:17 +03:00
return rw . Code , rw . Body . String ( )
}
func TestForwardAccessTokenUpstream ( t * testing . T ) {
2018-11-29 17:26:41 +03:00
patTest := NewPassAccessTokenTest ( PassAccessTokenTestOptions {
2015-04-03 03:57:17 +03:00
PassAccessToken : true ,
} )
2018-11-29 17:26:41 +03:00
defer patTest . Close ( )
2015-04-03 03:57:17 +03:00
// A successful validation will redirect and set the auth cookie.
2018-11-29 17:26:41 +03:00
code , cookie := patTest . getCallbackEndpoint ( )
2017-03-28 04:14:38 +03:00
if code != 302 {
t . Fatalf ( "expected 302; got %d" , code )
}
2015-04-03 03:57:17 +03:00
assert . NotEqual ( t , nil , cookie )
// Now we make a regular request; the access_token from the cookie is
// forwarded as the "X-Forwarded-Access-Token" header. The token is
// read by the test provider server and written in the response body.
2018-11-29 17:26:41 +03:00
code , payload := patTest . getRootEndpoint ( cookie )
2017-03-28 04:14:38 +03:00
if code != 200 {
t . Fatalf ( "expected 200; got %d" , code )
}
2015-04-03 03:57:17 +03:00
assert . Equal ( t , "my_auth_token" , payload )
}
func TestDoNotForwardAccessTokenUpstream ( t * testing . T ) {
2018-11-29 17:26:41 +03:00
patTest := NewPassAccessTokenTest ( PassAccessTokenTestOptions {
2015-04-03 03:57:17 +03:00
PassAccessToken : false ,
} )
2018-11-29 17:26:41 +03:00
defer patTest . Close ( )
2015-04-03 03:57:17 +03:00
// A successful validation will redirect and set the auth cookie.
2018-11-29 17:26:41 +03:00
code , cookie := patTest . getCallbackEndpoint ( )
2017-03-28 04:14:38 +03:00
if code != 302 {
t . Fatalf ( "expected 302; got %d" , code )
}
2015-04-03 03:57:17 +03:00
assert . NotEqual ( t , nil , cookie )
// Now we make a regular request, but the access token header should
// not be present.
2018-11-29 17:26:41 +03:00
code , payload := patTest . getRootEndpoint ( cookie )
2017-03-28 04:14:38 +03:00
if code != 200 {
t . Fatalf ( "expected 200; got %d" , code )
}
2015-04-03 03:57:17 +03:00
assert . Equal ( t , "No access token found." , payload )
}
2015-04-07 05:10:03 +03:00
type SignInPageTest struct {
2018-11-29 17:26:41 +03:00
opts * Options
proxy * OAuthProxy
signInRegexp * regexp . Regexp
signInProviderRegexp * regexp . Regexp
2015-04-07 05:10:03 +03:00
}
const signInRedirectPattern = ` <input type="hidden" name="rd" value="(.*)"> `
2017-06-22 01:02:34 +03:00
const signInSkipProvider = ` >Found< `
2015-04-07 05:10:03 +03:00
2017-06-22 01:02:34 +03:00
func NewSignInPageTest ( skipProvider bool ) * SignInPageTest {
2018-11-29 17:26:41 +03:00
var sipTest SignInPageTest
2015-04-07 05:10:03 +03:00
2018-11-29 17:26:41 +03:00
sipTest . opts = NewOptions ( )
sipTest . opts . CookieSecret = "foobar"
sipTest . opts . ClientID = "bazquux"
sipTest . opts . ClientSecret = "xyzzyplugh"
sipTest . opts . SkipProviderButton = skipProvider
sipTest . opts . Validate ( )
2015-04-07 05:10:03 +03:00
2018-11-29 17:26:41 +03:00
sipTest . proxy = NewOAuthProxy ( sipTest . opts , func ( email string ) bool {
2015-04-07 05:10:03 +03:00
return true
} )
2018-11-29 17:26:41 +03:00
sipTest . signInRegexp = regexp . MustCompile ( signInRedirectPattern )
sipTest . signInProviderRegexp = regexp . MustCompile ( signInSkipProvider )
2015-04-07 05:10:03 +03:00
2018-11-29 17:26:41 +03:00
return & sipTest
2015-04-07 05:10:03 +03:00
}
2018-11-29 17:26:41 +03:00
func ( sipTest * SignInPageTest ) GetEndpoint ( endpoint string ) ( int , string ) {
2015-04-07 05:10:03 +03:00
rw := httptest . NewRecorder ( )
req , _ := http . NewRequest ( "GET" , endpoint , strings . NewReader ( "" ) )
2018-11-29 17:26:41 +03:00
sipTest . proxy . ServeHTTP ( rw , req )
2015-04-07 05:10:03 +03:00
return rw . Code , rw . Body . String ( )
}
func TestSignInPageIncludesTargetRedirect ( t * testing . T ) {
2018-11-29 17:26:41 +03:00
sipTest := NewSignInPageTest ( false )
2015-04-07 05:10:03 +03:00
const endpoint = "/some/random/endpoint"
2018-11-29 17:26:41 +03:00
code , body := sipTest . GetEndpoint ( endpoint )
2015-04-07 05:10:03 +03:00
assert . Equal ( t , 403 , code )
2018-11-29 17:26:41 +03:00
match := sipTest . signInRegexp . FindStringSubmatch ( body )
2015-04-07 05:10:03 +03:00
if match == nil {
t . Fatal ( "Did not find pattern in body: " +
signInRedirectPattern + "\nBody:\n" + body )
}
if match [ 1 ] != endpoint {
t . Fatal ( ` expected redirect to " ` + endpoint +
` ", but was " ` + match [ 1 ] + ` " ` )
}
}
func TestSignInPageDirectAccessRedirectsToRoot ( t * testing . T ) {
2018-11-29 17:26:41 +03:00
sipTest := NewSignInPageTest ( false )
code , body := sipTest . GetEndpoint ( "/oauth2/sign_in" )
2015-04-07 05:10:03 +03:00
assert . Equal ( t , 200 , code )
2018-11-29 17:26:41 +03:00
match := sipTest . signInRegexp . FindStringSubmatch ( body )
2015-04-07 05:10:03 +03:00
if match == nil {
t . Fatal ( "Did not find pattern in body: " +
signInRedirectPattern + "\nBody:\n" + body )
}
if match [ 1 ] != "/" {
t . Fatal ( ` expected redirect to "/", but was " ` + match [ 1 ] + ` " ` )
}
}
2015-05-08 18:52:03 +03:00
2017-06-22 01:02:34 +03:00
func TestSignInPageSkipProvider ( t * testing . T ) {
2018-11-29 17:26:41 +03:00
sipTest := NewSignInPageTest ( true )
2017-06-22 01:02:34 +03:00
const endpoint = "/some/random/endpoint"
2018-11-29 17:26:41 +03:00
code , body := sipTest . GetEndpoint ( endpoint )
2017-06-22 01:02:34 +03:00
assert . Equal ( t , 302 , code )
2018-11-29 17:26:41 +03:00
match := sipTest . signInProviderRegexp . FindStringSubmatch ( body )
2017-06-22 01:02:34 +03:00
if match == nil {
t . Fatal ( "Did not find pattern in body: " +
signInSkipProvider + "\nBody:\n" + body )
}
}
func TestSignInPageSkipProviderDirect ( t * testing . T ) {
2018-11-29 17:26:41 +03:00
sipTest := NewSignInPageTest ( true )
2017-06-22 01:02:34 +03:00
const endpoint = "/sign_in"
2018-11-29 17:26:41 +03:00
code , body := sipTest . GetEndpoint ( endpoint )
2017-06-22 01:02:34 +03:00
assert . Equal ( t , 302 , code )
2018-11-29 17:26:41 +03:00
match := sipTest . signInProviderRegexp . FindStringSubmatch ( body )
2017-06-22 01:02:34 +03:00
if match == nil {
t . Fatal ( "Did not find pattern in body: " +
signInSkipProvider + "\nBody:\n" + body )
}
}
2015-05-08 18:52:03 +03:00
type ProcessCookieTest struct {
2018-11-29 17:26:41 +03:00
opts * Options
proxy * OAuthProxy
rw * httptest . ResponseRecorder
req * http . Request
provider TestProvider
responseCode int
validateUser bool
2015-05-08 18:52:03 +03:00
}
2015-05-13 04:48:13 +03:00
type ProcessCookieTestOpts struct {
2018-11-29 17:26:41 +03:00
providerValidateCookieResponse bool
2015-05-13 04:48:13 +03:00
}
func NewProcessCookieTest ( opts ProcessCookieTestOpts ) * ProcessCookieTest {
2018-11-29 17:26:41 +03:00
var pcTest ProcessCookieTest
2015-05-08 18:52:03 +03:00
2018-11-29 17:26:41 +03:00
pcTest . opts = NewOptions ( )
pcTest . opts . ClientID = "bazquux"
pcTest . opts . ClientSecret = "xyzzyplugh"
pcTest . opts . CookieSecret = "0123456789abcdefabcd"
2015-05-09 23:08:55 +03:00
// First, set the CookieRefresh option so proxy.AesCipher is created,
// needed to encrypt the access_token.
2018-11-29 17:26:41 +03:00
pcTest . opts . CookieRefresh = time . Hour
pcTest . opts . Validate ( )
2015-05-08 18:52:03 +03:00
2018-11-29 17:26:41 +03:00
pcTest . proxy = NewOAuthProxy ( pcTest . opts , func ( email string ) bool {
return pcTest . validateUser
2015-05-08 18:52:03 +03:00
} )
2018-11-29 17:26:41 +03:00
pcTest . proxy . provider = & TestProvider {
ValidToken : opts . providerValidateCookieResponse ,
2015-05-13 04:48:13 +03:00
}
2015-05-08 18:52:03 +03:00
2015-05-09 23:08:55 +03:00
// Now, zero-out proxy.CookieRefresh for the cases that don't involve
// access_token validation.
2018-11-29 17:26:41 +03:00
pcTest . proxy . CookieRefresh = time . Duration ( 0 )
pcTest . rw = httptest . NewRecorder ( )
pcTest . req , _ = http . NewRequest ( "GET" , "/" , strings . NewReader ( "" ) )
pcTest . validateUser = true
return & pcTest
2015-05-08 18:52:03 +03:00
}
2015-05-13 04:48:13 +03:00
func NewProcessCookieTestWithDefaults ( ) * ProcessCookieTest {
return NewProcessCookieTest ( ProcessCookieTestOpts {
2018-11-29 17:26:41 +03:00
providerValidateCookieResponse : true ,
2015-05-13 04:48:13 +03:00
} )
2015-05-09 22:09:31 +03:00
}
2018-01-28 01:48:52 +03:00
func ( p * ProcessCookieTest ) MakeCookie ( value string , ref time . Time ) [ ] * http . Cookie {
2017-03-28 04:14:38 +03:00
return p . proxy . MakeSessionCookie ( p . req , value , p . opts . CookieExpire , ref )
2015-05-08 18:52:03 +03:00
}
2015-06-23 14:23:39 +03:00
func ( p * ProcessCookieTest ) SaveSession ( s * providers . SessionState , ref time . Time ) error {
value , err := p . proxy . provider . CookieForSession ( s , p . proxy . CookieCipher )
if err != nil {
return err
}
2018-01-28 01:48:52 +03:00
for _ , c := range p . proxy . MakeSessionCookie ( p . req , value , p . proxy . CookieExpire , ref ) {
p . req . AddCookie ( c )
}
2015-06-23 14:23:39 +03:00
return nil
2015-05-08 18:52:03 +03:00
}
2015-06-23 14:23:39 +03:00
func ( p * ProcessCookieTest ) LoadCookiedSession ( ) ( * providers . SessionState , time . Duration , error ) {
return p . proxy . LoadCookiedSession ( p . req )
2015-05-08 18:52:03 +03:00
}
2015-06-23 14:23:39 +03:00
func TestLoadCookiedSession ( t * testing . T ) {
2018-11-29 17:26:41 +03:00
pcTest := NewProcessCookieTestWithDefaults ( )
2015-05-09 22:09:31 +03:00
2015-06-23 14:23:39 +03:00
startSession := & providers . SessionState { Email : "michael.bland@gsa.gov" , AccessToken : "my_access_token" }
2018-11-29 17:26:41 +03:00
pcTest . SaveSession ( startSession , time . Now ( ) )
2015-06-23 14:23:39 +03:00
2018-11-29 17:26:41 +03:00
session , _ , err := pcTest . LoadCookiedSession ( )
2015-06-23 14:23:39 +03:00
assert . Equal ( t , nil , err )
assert . Equal ( t , startSession . Email , session . Email )
assert . Equal ( t , "michael.bland" , session . User )
assert . Equal ( t , startSession . AccessToken , session . AccessToken )
2015-05-08 18:52:03 +03:00
}
2015-05-08 17:00:57 +03:00
func TestProcessCookieNoCookieError ( t * testing . T ) {
2018-11-29 17:26:41 +03:00
pcTest := NewProcessCookieTestWithDefaults ( )
2015-05-08 17:00:57 +03:00
2018-11-29 17:26:41 +03:00
session , _ , err := pcTest . LoadCookiedSession ( )
2015-06-23 14:23:39 +03:00
assert . Equal ( t , "Cookie \"_oauth2_proxy\" not present" , err . Error ( ) )
if session != nil {
t . Errorf ( "expected nil session. got %#v" , session )
}
2015-05-09 23:31:18 +03:00
}
2015-05-08 17:00:57 +03:00
func TestProcessCookieRefreshNotSet ( t * testing . T ) {
2018-11-29 17:26:41 +03:00
pcTest := NewProcessCookieTestWithDefaults ( )
pcTest . proxy . CookieExpire = time . Duration ( 23 ) * time . Hour
2015-06-22 22:10:08 +03:00
reference := time . Now ( ) . Add ( time . Duration ( - 2 ) * time . Hour )
2015-05-08 17:00:57 +03:00
2015-06-23 14:23:39 +03:00
startSession := & providers . SessionState { Email : "michael.bland@gsa.gov" , AccessToken : "my_access_token" }
2018-11-29 17:26:41 +03:00
pcTest . SaveSession ( startSession , reference )
2015-05-09 22:09:31 +03:00
2018-11-29 17:26:41 +03:00
session , age , err := pcTest . LoadCookiedSession ( )
2015-06-23 14:23:39 +03:00
assert . Equal ( t , nil , err )
if age < time . Duration ( - 2 ) * time . Hour {
t . Errorf ( "cookie too young %v" , age )
}
assert . Equal ( t , startSession . Email , session . Email )
2015-05-10 07:11:26 +03:00
}
2015-06-22 22:10:08 +03:00
func TestProcessCookieFailIfCookieExpired ( t * testing . T ) {
2018-11-29 17:26:41 +03:00
pcTest := NewProcessCookieTestWithDefaults ( )
pcTest . proxy . CookieExpire = time . Duration ( 24 ) * time . Hour
2015-06-22 22:10:08 +03:00
reference := time . Now ( ) . Add ( time . Duration ( 25 ) * time . Hour * - 1 )
2015-06-23 14:23:39 +03:00
startSession := & providers . SessionState { Email : "michael.bland@gsa.gov" , AccessToken : "my_access_token" }
2018-11-29 17:26:41 +03:00
pcTest . SaveSession ( startSession , reference )
2015-06-22 22:10:08 +03:00
2018-11-29 17:26:41 +03:00
session , _ , err := pcTest . LoadCookiedSession ( )
2015-06-23 14:23:39 +03:00
assert . NotEqual ( t , nil , err )
if session != nil {
t . Errorf ( "expected nil session %#v" , session )
2015-06-22 22:10:08 +03:00
}
}
func TestProcessCookieFailIfRefreshSetAndCookieExpired ( t * testing . T ) {
2018-11-29 17:26:41 +03:00
pcTest := NewProcessCookieTestWithDefaults ( )
pcTest . proxy . CookieExpire = time . Duration ( 24 ) * time . Hour
2015-06-22 22:10:08 +03:00
reference := time . Now ( ) . Add ( time . Duration ( 25 ) * time . Hour * - 1 )
2015-06-23 14:23:39 +03:00
startSession := & providers . SessionState { Email : "michael.bland@gsa.gov" , AccessToken : "my_access_token" }
2018-11-29 17:26:41 +03:00
pcTest . SaveSession ( startSession , reference )
2015-06-22 22:10:08 +03:00
2018-11-29 17:26:41 +03:00
pcTest . proxy . CookieRefresh = time . Hour
session , _ , err := pcTest . LoadCookiedSession ( )
2015-06-23 14:23:39 +03:00
assert . NotEqual ( t , nil , err )
if session != nil {
t . Errorf ( "expected nil session %#v" , session )
2015-06-22 22:10:08 +03:00
}
}
2015-10-08 16:27:00 +03:00
func NewAuthOnlyEndpointTest ( ) * ProcessCookieTest {
2018-11-29 17:26:41 +03:00
pcTest := NewProcessCookieTestWithDefaults ( )
pcTest . req , _ = http . NewRequest ( "GET" ,
pcTest . opts . ProxyPrefix + "/auth" , nil )
return pcTest
2015-10-08 16:27:00 +03:00
}
func TestAuthOnlyEndpointAccepted ( t * testing . T ) {
test := NewAuthOnlyEndpointTest ( )
startSession := & providers . SessionState {
Email : "michael.bland@gsa.gov" , AccessToken : "my_access_token" }
test . SaveSession ( startSession , time . Now ( ) )
test . proxy . ServeHTTP ( test . rw , test . req )
assert . Equal ( t , http . StatusAccepted , test . rw . Code )
bodyBytes , _ := ioutil . ReadAll ( test . rw . Body )
assert . Equal ( t , "" , string ( bodyBytes ) )
}
func TestAuthOnlyEndpointUnauthorizedOnNoCookieSetError ( t * testing . T ) {
test := NewAuthOnlyEndpointTest ( )
test . proxy . ServeHTTP ( test . rw , test . req )
assert . Equal ( t , http . StatusUnauthorized , test . rw . Code )
bodyBytes , _ := ioutil . ReadAll ( test . rw . Body )
assert . Equal ( t , "unauthorized request\n" , string ( bodyBytes ) )
}
func TestAuthOnlyEndpointUnauthorizedOnExpiration ( t * testing . T ) {
test := NewAuthOnlyEndpointTest ( )
test . proxy . CookieExpire = time . Duration ( 24 ) * time . Hour
reference := time . Now ( ) . Add ( time . Duration ( 25 ) * time . Hour * - 1 )
startSession := & providers . SessionState {
Email : "michael.bland@gsa.gov" , AccessToken : "my_access_token" }
test . SaveSession ( startSession , reference )
test . proxy . ServeHTTP ( test . rw , test . req )
assert . Equal ( t , http . StatusUnauthorized , test . rw . Code )
bodyBytes , _ := ioutil . ReadAll ( test . rw . Body )
assert . Equal ( t , "unauthorized request\n" , string ( bodyBytes ) )
}
func TestAuthOnlyEndpointUnauthorizedOnEmailValidationFailure ( t * testing . T ) {
test := NewAuthOnlyEndpointTest ( )
startSession := & providers . SessionState {
Email : "michael.bland@gsa.gov" , AccessToken : "my_access_token" }
test . SaveSession ( startSession , time . Now ( ) )
2018-11-29 17:26:41 +03:00
test . validateUser = false
2015-10-08 16:27:00 +03:00
test . proxy . ServeHTTP ( test . rw , test . req )
assert . Equal ( t , http . StatusUnauthorized , test . rw . Code )
bodyBytes , _ := ioutil . ReadAll ( test . rw . Body )
assert . Equal ( t , "unauthorized request\n" , string ( bodyBytes ) )
}
2015-11-16 06:08:30 +03:00
2016-10-20 15:19:59 +03:00
func TestAuthOnlyEndpointSetXAuthRequestHeaders ( t * testing . T ) {
2018-11-29 17:26:41 +03:00
var pcTest ProcessCookieTest
2016-10-20 15:19:59 +03:00
2018-11-29 17:26:41 +03:00
pcTest . opts = NewOptions ( )
pcTest . opts . SetXAuthRequest = true
pcTest . opts . Validate ( )
2016-10-20 15:19:59 +03:00
2018-11-29 17:26:41 +03:00
pcTest . proxy = NewOAuthProxy ( pcTest . opts , func ( email string ) bool {
return pcTest . validateUser
2016-10-20 15:19:59 +03:00
} )
2018-11-29 17:26:41 +03:00
pcTest . proxy . provider = & TestProvider {
2016-10-20 15:19:59 +03:00
ValidToken : true ,
}
2018-11-29 17:26:41 +03:00
pcTest . validateUser = true
2016-10-20 15:19:59 +03:00
2018-11-29 17:26:41 +03:00
pcTest . rw = httptest . NewRecorder ( )
pcTest . req , _ = http . NewRequest ( "GET" ,
pcTest . opts . ProxyPrefix + "/auth" , nil )
2016-10-20 15:19:59 +03:00
startSession := & providers . SessionState {
User : "oauth_user" , Email : "oauth_user@example.com" , AccessToken : "oauth_token" }
2018-11-29 17:26:41 +03:00
pcTest . SaveSession ( startSession , time . Now ( ) )
2016-10-20 15:19:59 +03:00
2018-11-29 17:26:41 +03:00
pcTest . proxy . ServeHTTP ( pcTest . rw , pcTest . req )
assert . Equal ( t , http . StatusAccepted , pcTest . rw . Code )
assert . Equal ( t , "oauth_user" , pcTest . rw . HeaderMap [ "X-Auth-Request-User" ] [ 0 ] )
assert . Equal ( t , "oauth_user@example.com" , pcTest . rw . HeaderMap [ "X-Auth-Request-Email" ] [ 0 ] )
2016-10-20 15:19:59 +03:00
}
2017-04-07 14:55:48 +03:00
func TestAuthSkippedForPreflightRequests ( t * testing . T ) {
upstream := httptest . NewServer ( http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
w . WriteHeader ( 200 )
w . Write ( [ ] byte ( "response" ) )
} ) )
defer upstream . Close ( )
opts := NewOptions ( )
opts . Upstreams = append ( opts . Upstreams , upstream . URL )
opts . ClientID = "bazquux"
opts . ClientSecret = "foobar"
opts . CookieSecret = "xyzzyplugh"
opts . SkipAuthPreflight = true
opts . Validate ( )
2018-11-29 17:26:41 +03:00
upstreamURL , _ := url . Parse ( upstream . URL )
opts . provider = NewTestProvider ( upstreamURL , "" )
2017-04-07 14:55:48 +03:00
proxy := NewOAuthProxy ( opts , func ( string ) bool { return false } )
rw := httptest . NewRecorder ( )
req , _ := http . NewRequest ( "OPTIONS" , "/preflight-request" , nil )
proxy . ServeHTTP ( rw , req )
assert . Equal ( t , 200 , rw . Code )
assert . Equal ( t , "response" , rw . Body . String ( ) )
}
2015-11-16 06:08:30 +03:00
type SignatureAuthenticator struct {
auth hmacauth . HmacAuth
}
2017-03-23 06:18:34 +03:00
func ( v * SignatureAuthenticator ) Authenticate ( w http . ResponseWriter , r * http . Request ) {
2015-11-16 06:08:30 +03:00
result , headerSig , computedSig := v . auth . AuthenticateRequest ( r )
if result == hmacauth . ResultNoSignature {
w . Write ( [ ] byte ( "no signature received" ) )
} else if result == hmacauth . ResultMatch {
w . Write ( [ ] byte ( "signatures match" ) )
} else if result == hmacauth . ResultMismatch {
w . Write ( [ ] byte ( "signatures do not match:" +
"\n received: " + headerSig +
"\n computed: " + computedSig ) )
} else {
panic ( "Unknown result value: " + result . String ( ) )
}
}
type SignatureTest struct {
opts * Options
upstream * httptest . Server
2018-11-29 17:26:41 +03:00
upstreamHost string
2015-11-16 06:08:30 +03:00
provider * httptest . Server
header http . Header
rw * httptest . ResponseRecorder
authenticator * SignatureAuthenticator
}
func NewSignatureTest ( ) * SignatureTest {
opts := NewOptions ( )
opts . CookieSecret = "cookie secret"
opts . ClientID = "client ID"
opts . ClientSecret = "client secret"
opts . EmailDomains = [ ] string { "acm.org" }
authenticator := & SignatureAuthenticator { }
upstream := httptest . NewServer (
http . HandlerFunc ( authenticator . Authenticate ) )
2018-11-29 17:26:41 +03:00
upstreamURL , _ := url . Parse ( upstream . URL )
2015-11-16 06:08:30 +03:00
opts . Upstreams = append ( opts . Upstreams , upstream . URL )
providerHandler := func ( w http . ResponseWriter , r * http . Request ) {
w . Write ( [ ] byte ( ` { "access_token": "my_auth_token"} ` ) )
}
provider := httptest . NewServer ( http . HandlerFunc ( providerHandler ) )
2018-11-29 17:26:41 +03:00
providerURL , _ := url . Parse ( provider . URL )
opts . provider = NewTestProvider ( providerURL , "mbland@acm.org" )
2015-11-16 06:08:30 +03:00
return & SignatureTest {
opts ,
upstream ,
2018-11-29 17:26:41 +03:00
upstreamURL . Host ,
2015-11-16 06:08:30 +03:00
provider ,
make ( http . Header ) ,
httptest . NewRecorder ( ) ,
authenticator ,
}
}
func ( st * SignatureTest ) Close ( ) {
st . provider . Close ( )
st . upstream . Close ( )
}
// fakeNetConn simulates an http.Request.Body buffer that will be consumed
// when it is read by the hmacauth.HmacAuth if not handled properly. See:
// https://github.com/18F/hmacauth/pull/4
type fakeNetConn struct {
reqBody string
}
func ( fnc * fakeNetConn ) Read ( p [ ] byte ) ( n int , err error ) {
if bodyLen := len ( fnc . reqBody ) ; bodyLen != 0 {
copy ( p , fnc . reqBody )
fnc . reqBody = ""
return bodyLen , io . EOF
}
return 0 , io . EOF
}
func ( st * SignatureTest ) MakeRequestWithExpectedKey ( method , body , key string ) {
err := st . opts . Validate ( )
if err != nil {
panic ( err )
}
proxy := NewOAuthProxy ( st . opts , func ( email string ) bool { return true } )
var bodyBuf io . ReadCloser
if body != "" {
bodyBuf = ioutil . NopCloser ( & fakeNetConn { reqBody : body } )
}
2017-03-23 06:18:34 +03:00
req := httptest . NewRequest ( method , "/foo/bar" , bodyBuf )
2015-11-16 06:08:30 +03:00
req . Header = st . header
state := & providers . SessionState {
Email : "mbland@acm.org" , AccessToken : "my_access_token" }
value , err := proxy . provider . CookieForSession ( state , proxy . CookieCipher )
if err != nil {
panic ( err )
}
2018-01-28 01:48:52 +03:00
for _ , c := range proxy . MakeSessionCookie ( req , value , proxy . CookieExpire , time . Now ( ) ) {
req . AddCookie ( c )
}
2015-11-16 06:08:30 +03:00
// This is used by the upstream to validate the signature.
st . authenticator . auth = hmacauth . NewHmacAuth (
crypto . SHA1 , [ ] byte ( key ) , SignatureHeader , SignatureHeaders )
proxy . ServeHTTP ( st . rw , req )
}
func TestNoRequestSignature ( t * testing . T ) {
st := NewSignatureTest ( )
defer st . Close ( )
st . MakeRequestWithExpectedKey ( "GET" , "" , "" )
assert . Equal ( t , 200 , st . rw . Code )
assert . Equal ( t , st . rw . Body . String ( ) , "no signature received" )
}
func TestRequestSignatureGetRequest ( t * testing . T ) {
st := NewSignatureTest ( )
defer st . Close ( )
st . opts . SignatureKey = "sha1:foobar"
st . MakeRequestWithExpectedKey ( "GET" , "" , "foobar" )
assert . Equal ( t , 200 , st . rw . Code )
assert . Equal ( t , st . rw . Body . String ( ) , "signatures match" )
}
func TestRequestSignaturePostRequest ( t * testing . T ) {
st := NewSignatureTest ( )
defer st . Close ( )
st . opts . SignatureKey = "sha1:foobar"
payload := ` { "hello": "world!" } `
st . MakeRequestWithExpectedKey ( "POST" , payload , "foobar" )
assert . Equal ( t , 200 , st . rw . Code )
assert . Equal ( t , st . rw . Body . String ( ) , "signatures match" )
}
2019-01-29 15:13:02 +03:00
func TestGetRedirect ( t * testing . T ) {
options := NewOptions ( )
_ = options . Validate ( )
require . NotEmpty ( t , options . ProxyPrefix )
proxy := NewOAuthProxy ( options , func ( s string ) bool { return false } )
tests := [ ] struct {
name string
url string
expectedRedirect string
} {
{
name : "request outside of ProxyPrefix redirects to original URL" ,
url : "/foo/bar" ,
expectedRedirect : "/foo/bar" ,
} ,
{
name : "request under ProxyPrefix redirects to root" ,
url : proxy . ProxyPrefix + "/foo/bar" ,
expectedRedirect : "/" ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
req , _ := http . NewRequest ( "GET" , tt . url , nil )
redirect , err := proxy . GetRedirect ( req )
assert . NoError ( t , err )
assert . Equal ( t , tt . expectedRedirect , redirect )
} )
}
}
2019-01-30 13:13:12 +03:00
type ajaxRequestTest struct {
opts * Options
proxy * OAuthProxy
}
func newAjaxRequestTest ( ) * ajaxRequestTest {
test := & ajaxRequestTest { }
test . opts = NewOptions ( )
test . opts . CookieSecret = "foobar"
test . opts . ClientID = "bazquux"
test . opts . ClientSecret = "xyzzyplugh"
test . opts . Validate ( )
test . proxy = NewOAuthProxy ( test . opts , func ( email string ) bool {
return true
} )
return test
}
func ( test * ajaxRequestTest ) getEndpoint ( endpoint string , header http . Header ) ( int , http . Header , error ) {
rw := httptest . NewRecorder ( )
req , err := http . NewRequest ( http . MethodGet , endpoint , strings . NewReader ( "" ) )
if err != nil {
return 0 , nil , err
}
req . Header = header
test . proxy . ServeHTTP ( rw , req )
return rw . Code , rw . Header ( ) , nil
}
func testAjaxUnauthorizedRequest ( t * testing . T , header http . Header ) {
test := newAjaxRequestTest ( )
2019-01-31 18:22:30 +03:00
endpoint := "/test"
2019-01-30 13:13:12 +03:00
code , rh , err := test . getEndpoint ( endpoint , header )
assert . NoError ( t , err )
assert . Equal ( t , http . StatusUnauthorized , code )
mime := rh . Get ( "Content-Type" )
2019-01-31 18:22:30 +03:00
assert . Equal ( t , applicationJSON , mime )
2019-01-30 13:13:12 +03:00
}
func TestAjaxUnauthorizedRequest1 ( t * testing . T ) {
header := make ( http . Header )
2019-01-31 18:22:30 +03:00
header . Add ( "accept" , applicationJSON )
2019-01-30 13:13:12 +03:00
testAjaxUnauthorizedRequest ( t , header )
}
func TestAjaxUnauthorizedRequest2 ( t * testing . T ) {
header := make ( http . Header )
2019-01-31 18:22:30 +03:00
header . Add ( "Accept" , applicationJSON )
2019-01-30 13:13:12 +03:00
testAjaxUnauthorizedRequest ( t , header )
}
func TestAjaxForbiddendRequest ( t * testing . T ) {
test := newAjaxRequestTest ( )
2019-01-31 18:22:30 +03:00
endpoint := "/test"
2019-01-30 13:13:12 +03:00
header := make ( http . Header )
code , rh , err := test . getEndpoint ( endpoint , header )
assert . NoError ( t , err )
assert . Equal ( t , http . StatusForbidden , code )
mime := rh . Get ( "Content-Type" )
2019-01-31 18:22:30 +03:00
assert . NotEqual ( t , applicationJSON , mime )
2019-01-30 13:13:12 +03:00
}
2019-03-15 10:18:37 +03:00
func TestClearSplitCookie ( t * testing . T ) {
p := OAuthProxy { CookieName : "oauth2" , CookieDomain : "abc" }
var rw = httptest . NewRecorder ( )
req := httptest . NewRequest ( "get" , "/" , nil )
req . AddCookie ( & http . Cookie {
Name : "test1" ,
Value : "test1" ,
} )
req . AddCookie ( & http . Cookie {
Name : "oauth2_0" ,
Value : "oauth2_0" ,
} )
req . AddCookie ( & http . Cookie {
Name : "oauth2_1" ,
Value : "oauth2_1" ,
} )
p . ClearSessionCookie ( rw , req )
header := rw . Header ( )
assert . Equal ( t , 2 , len ( header [ "Set-Cookie" ] ) , "should have 3 set-cookie header entries" )
}
func TestClearSingleCookie ( t * testing . T ) {
p := OAuthProxy { CookieName : "oauth2" , CookieDomain : "abc" }
var rw = httptest . NewRecorder ( )
req := httptest . NewRequest ( "get" , "/" , nil )
req . AddCookie ( & http . Cookie {
Name : "test1" ,
Value : "test1" ,
} )
req . AddCookie ( & http . Cookie {
Name : "oauth2" ,
Value : "oauth2" ,
} )
p . ClearSessionCookie ( rw , req )
header := rw . Header ( )
assert . Equal ( t , 1 , len ( header [ "Set-Cookie" ] ) , "should have 1 set-cookie header entries" )
}