371 lines
12 KiB
Go
371 lines
12 KiB
Go
package providers
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"log"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
var (
|
|
path_group string = "/v1.0/me/memberOf?$select=displayName"
|
|
path_group_next string = "/v1.0/me/memberOf?$select=displayName&$skiptoken=X%27test-token%27"
|
|
path_group_wrong string = "/v1.0/him/memberOf?$select=displayName"
|
|
payload_group_empty string = `{"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#directoryObjects(displayName)","value":[]}`
|
|
payload_group_garbage string = `{"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#directoryObjects(displayName)","value":[{"@odata.type":"#microsoft.graph.group","displayName":"test-group-1"},{"@odata.type":"#microsoft.graph.group","displayName":"test-group-2"}]}`
|
|
payload_group_simple string = `{"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#directoryObjects(displayName)","value":[{"@odata.type":"#microsoft.graph.group","displayName":"test-group-1"},{"@odata.type":"#microsoft.graph.group","displayName":"test-group-2"}]}`
|
|
payload_group_part_1 string = `{"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#directoryObjects(displayName)","@odata.nextLink":"https://graph.microsoft.com/v1.0/me/memberOf?$select=displayName&$skiptoken=X%27test-token%27","value":[{"@odata.type":"#microsoft.graph.group","displayName":"test-group-1"},{"@odata.type":"#microsoft.graph.group","displayName":"test-group-2"}]}`
|
|
payload_group_part_2 string = `{"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#directoryObjects(displayName)","value":[{"@odata.type":"#microsoft.graph.group","displayName":"test-group-3"}]}`
|
|
)
|
|
|
|
type mockTransport struct {
|
|
params map[string]string
|
|
}
|
|
|
|
func (t *mockTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
log.Printf("Starting Round Tripper")
|
|
// Create mocked http.Response
|
|
response := &http.Response{
|
|
Header: make(http.Header),
|
|
Request: req,
|
|
StatusCode: http.StatusOK,
|
|
}
|
|
response.Header.Set("Content-Type", "application/json")
|
|
|
|
//url := req.URL
|
|
full_request := req.URL.Path
|
|
if req.URL.RawQuery != "" {
|
|
full_request += "?" + req.URL.RawQuery
|
|
}
|
|
var err error
|
|
if value, ok := t.params[full_request]; ok {
|
|
if req.Header.Get("Authorization") != "Bearer imaginary_access_token" {
|
|
response.StatusCode = http.StatusForbidden
|
|
err = fmt.Errorf("got 403. Bearer token '%v' is not correct", req.Header.Get("Authorization"))
|
|
} else {
|
|
response.StatusCode = http.StatusOK
|
|
response.Body = ioutil.NopCloser(strings.NewReader(value))
|
|
err = nil
|
|
}
|
|
|
|
} else {
|
|
response.StatusCode = http.StatusNotFound
|
|
err = fmt.Errorf("got 404. Requested path '%v' is not found", full_request)
|
|
}
|
|
|
|
return response, err
|
|
}
|
|
|
|
func newMockTransport(params map[string]string) http.RoundTripper {
|
|
return &mockTransport{params}
|
|
}
|
|
|
|
func testAzureProvider(hostname string) *AzureProvider {
|
|
p := NewAzureProvider(
|
|
&ProviderData{
|
|
ProviderName: "",
|
|
LoginURL: &url.URL{},
|
|
RedeemURL: &url.URL{},
|
|
ProfileURL: &url.URL{},
|
|
ValidateURL: &url.URL{},
|
|
ProtectedResource: &url.URL{},
|
|
Scope: ""})
|
|
|
|
if hostname != "" {
|
|
updateURL(p.Data().LoginURL, hostname)
|
|
updateURL(p.Data().RedeemURL, hostname)
|
|
updateURL(p.Data().ProfileURL, hostname)
|
|
updateURL(p.Data().ValidateURL, hostname)
|
|
updateURL(p.Data().ProtectedResource, hostname)
|
|
}
|
|
return p
|
|
}
|
|
|
|
func TestAzureProviderDefaults(t *testing.T) {
|
|
p := testAzureProvider("")
|
|
assert.NotEqual(t, nil, p)
|
|
p.Configure("")
|
|
assert.Equal(t, "Azure", p.Data().ProviderName)
|
|
assert.Equal(t, "common", p.Tenant)
|
|
assert.Equal(t, "https://login.microsoftonline.com/common/oauth2/authorize",
|
|
p.Data().LoginURL.String())
|
|
assert.Equal(t, "https://login.microsoftonline.com/common/oauth2/token",
|
|
p.Data().RedeemURL.String())
|
|
assert.Equal(t, "https://graph.microsoft.com/v1.0/me",
|
|
p.Data().ProfileURL.String())
|
|
assert.Equal(t, "https://graph.microsoft.com",
|
|
p.Data().ProtectedResource.String())
|
|
assert.Equal(t, "",
|
|
p.Data().ValidateURL.String())
|
|
assert.Equal(t, "openid", p.Data().Scope)
|
|
}
|
|
|
|
func TestAzureProviderOverrides(t *testing.T) {
|
|
p := NewAzureProvider(
|
|
&ProviderData{
|
|
LoginURL: &url.URL{
|
|
Scheme: "https",
|
|
Host: "example.com",
|
|
Path: "/oauth/auth"},
|
|
RedeemURL: &url.URL{
|
|
Scheme: "https",
|
|
Host: "example.com",
|
|
Path: "/oauth/token"},
|
|
ProfileURL: &url.URL{
|
|
Scheme: "https",
|
|
Host: "example.com",
|
|
Path: "/oauth/profile"},
|
|
ValidateURL: &url.URL{
|
|
Scheme: "https",
|
|
Host: "example.com",
|
|
Path: "/oauth/tokeninfo"},
|
|
ProtectedResource: &url.URL{
|
|
Scheme: "https",
|
|
Host: "example.com"},
|
|
Scope: "profile"})
|
|
assert.NotEqual(t, nil, p)
|
|
assert.Equal(t, "Azure", p.Data().ProviderName)
|
|
assert.Equal(t, "https://example.com/oauth/auth",
|
|
p.Data().LoginURL.String())
|
|
assert.Equal(t, "https://example.com/oauth/token",
|
|
p.Data().RedeemURL.String())
|
|
assert.Equal(t, "https://example.com/oauth/profile",
|
|
p.Data().ProfileURL.String())
|
|
assert.Equal(t, "https://example.com/oauth/tokeninfo",
|
|
p.Data().ValidateURL.String())
|
|
assert.Equal(t, "https://example.com",
|
|
p.Data().ProtectedResource.String())
|
|
assert.Equal(t, "profile", p.Data().Scope)
|
|
}
|
|
|
|
func TestAzureSetTenant(t *testing.T) {
|
|
p := testAzureProvider("")
|
|
p.Configure("example")
|
|
assert.Equal(t, "Azure", p.Data().ProviderName)
|
|
assert.Equal(t, "example", p.Tenant)
|
|
assert.Equal(t, "https://login.microsoftonline.com/example/oauth2/authorize",
|
|
p.Data().LoginURL.String())
|
|
assert.Equal(t, "https://login.microsoftonline.com/example/oauth2/token",
|
|
p.Data().RedeemURL.String())
|
|
assert.Equal(t, "https://graph.microsoft.com/v1.0/me",
|
|
p.Data().ProfileURL.String())
|
|
assert.Equal(t, "https://graph.microsoft.com",
|
|
p.Data().ProtectedResource.String())
|
|
assert.Equal(t, "",
|
|
p.Data().ValidateURL.String())
|
|
assert.Equal(t, "openid", p.Data().Scope)
|
|
}
|
|
|
|
func testAzureBackend(payload string) *httptest.Server {
|
|
path := "/v1.0/me"
|
|
query := ""
|
|
|
|
return httptest.NewServer(http.HandlerFunc(
|
|
func(w http.ResponseWriter, r *http.Request) {
|
|
url := r.URL
|
|
if url.Path != path || url.RawQuery != query {
|
|
w.WriteHeader(404)
|
|
} else if r.Header.Get("Authorization") != "Bearer imaginary_access_token" {
|
|
w.WriteHeader(403)
|
|
} else {
|
|
w.WriteHeader(200)
|
|
w.Write([]byte(payload))
|
|
}
|
|
}))
|
|
}
|
|
|
|
func TestAzureProviderGetEmailAddress(t *testing.T) {
|
|
b := testAzureBackend(`{ "mail": "user@windows.net" }`)
|
|
defer b.Close()
|
|
|
|
bURL, _ := url.Parse(b.URL)
|
|
p := testAzureProvider(bURL.Host)
|
|
|
|
session := &SessionState{AccessToken: "imaginary_access_token"}
|
|
email, err := p.GetEmailAddress(session)
|
|
assert.Equal(t, nil, err)
|
|
assert.Equal(t, "user@windows.net", email)
|
|
}
|
|
|
|
func TestAzureProviderGetEmailAddressMailNull(t *testing.T) {
|
|
b := testAzureBackend(`{ "mail": null, "otherMails": ["user@windows.net", "altuser@windows.net"] }`)
|
|
defer b.Close()
|
|
|
|
bURL, _ := url.Parse(b.URL)
|
|
p := testAzureProvider(bURL.Host)
|
|
|
|
session := &SessionState{AccessToken: "imaginary_access_token"}
|
|
email, err := p.GetEmailAddress(session)
|
|
assert.Equal(t, nil, err)
|
|
assert.Equal(t, "user@windows.net", email)
|
|
}
|
|
|
|
func TestAzureProviderGetEmailAddressGetUserPrincipalName(t *testing.T) {
|
|
b := testAzureBackend(`{ "mail": null, "otherMails": [], "userPrincipalName": "user@windows.net" }`)
|
|
defer b.Close()
|
|
|
|
bURL, _ := url.Parse(b.URL)
|
|
p := testAzureProvider(bURL.Host)
|
|
|
|
session := &SessionState{AccessToken: "imaginary_access_token"}
|
|
email, err := p.GetEmailAddress(session)
|
|
assert.Equal(t, nil, err)
|
|
assert.Equal(t, "user@windows.net", email)
|
|
}
|
|
|
|
func TestAzureProviderGetEmailAddressFailToGetEmailAddress(t *testing.T) {
|
|
b := testAzureBackend(`{ "mail": null, "otherMails": [], "userPrincipalName": null }`)
|
|
defer b.Close()
|
|
|
|
bURL, _ := url.Parse(b.URL)
|
|
p := testAzureProvider(bURL.Host)
|
|
|
|
session := &SessionState{AccessToken: "imaginary_access_token"}
|
|
email, err := p.GetEmailAddress(session)
|
|
assert.Equal(t, "type assertion to string failed", err.Error())
|
|
assert.Equal(t, "", email)
|
|
}
|
|
|
|
func TestAzureProviderGetEmailAddressEmptyUserPrincipalName(t *testing.T) {
|
|
b := testAzureBackend(`{ "mail": null, "otherMails": [], "userPrincipalName": "" }`)
|
|
defer b.Close()
|
|
|
|
bURL, _ := url.Parse(b.URL)
|
|
p := testAzureProvider(bURL.Host)
|
|
|
|
session := &SessionState{AccessToken: "imaginary_access_token"}
|
|
email, err := p.GetEmailAddress(session)
|
|
assert.Equal(t, nil, err)
|
|
assert.Equal(t, "", email)
|
|
}
|
|
|
|
func TestAzureProviderGetEmailAddressIncorrectOtherMails(t *testing.T) {
|
|
b := testAzureBackend(`{ "mail": null, "otherMails": "", "userPrincipalName": null }`)
|
|
defer b.Close()
|
|
|
|
bURL, _ := url.Parse(b.URL)
|
|
p := testAzureProvider(bURL.Host)
|
|
|
|
session := &SessionState{AccessToken: "imaginary_access_token"}
|
|
email, err := p.GetEmailAddress(session)
|
|
assert.Equal(t, "type assertion to string failed", err.Error())
|
|
assert.Equal(t, "", email)
|
|
}
|
|
|
|
func TestAzureProviderNoGroups(t *testing.T) {
|
|
params := map[string]string{
|
|
path_group: payload_group_empty}
|
|
|
|
http.DefaultClient.Transport = newMockTransport(params)
|
|
|
|
p := testAzureProvider("")
|
|
|
|
session := &SessionState{
|
|
AccessToken: "imaginary_access_token",
|
|
IDToken: "imaginary_IDToken_token"}
|
|
|
|
groups, err := p.GetGroups(session, "")
|
|
http.DefaultClient.Transport = nil
|
|
|
|
assert.Equal(t, nil, err)
|
|
// assert.Equal(t, "", groups)
|
|
assert.Equal(t, []string{}, groups)
|
|
}
|
|
|
|
func TestAzureProviderWrongRequestGroups(t *testing.T) {
|
|
params := map[string]string{
|
|
path_group_wrong: payload_group_part_1}
|
|
http.DefaultClient.Transport = newMockTransport(params)
|
|
log.Printf("Def %#v\n\n", http.DefaultClient.Transport)
|
|
|
|
p := testAzureProvider("")
|
|
|
|
session := &SessionState{
|
|
AccessToken: "imaginary_access_token",
|
|
IDToken: "imaginary_IDToken_token"}
|
|
|
|
groups, err := p.GetGroups(session, "")
|
|
http.DefaultClient.Transport = nil
|
|
|
|
assert.NotEqual(t, nil, err)
|
|
assert.Equal(t, []string{}, groups)
|
|
}
|
|
|
|
func TestAzureProviderMultiRequestsGroups(t *testing.T) {
|
|
params := map[string]string{
|
|
path_group: payload_group_part_1,
|
|
path_group_next: payload_group_part_2}
|
|
http.DefaultClient.Transport = newMockTransport(params)
|
|
|
|
p := testAzureProvider("")
|
|
|
|
session := &SessionState{
|
|
AccessToken: "imaginary_access_token",
|
|
IDToken: "imaginary_IDToken_token"}
|
|
|
|
groups, err := p.GetGroups(session, "")
|
|
http.DefaultClient.Transport = nil
|
|
|
|
assert.Equal(t, nil, err)
|
|
assert.Equal(t, []string{"test-group-1", "test-group-2", "test-group-3"}, groups)
|
|
}
|
|
|
|
func TestAzureEmptyPermittedGroups(t *testing.T) {
|
|
p := testAzureProvider("")
|
|
|
|
session := &SessionState{
|
|
AccessToken: "imaginary_access_token",
|
|
IDToken: "imaginary_IDToken_token",
|
|
Groups: "no one|cares|non existing|groups"}
|
|
result := p.ValidateGroup(session)
|
|
|
|
assert.Equal(t, true, result)
|
|
}
|
|
|
|
func TestAzureWrongPermittedGroups(t *testing.T) {
|
|
p := testAzureProvider("")
|
|
p.SetGroupRestriction([]string{"test-group-2"})
|
|
|
|
session := &SessionState{
|
|
AccessToken: "imaginary_access_token",
|
|
IDToken: "imaginary_IDToken_token",
|
|
Groups: "no one|cares|non existing|groups|test-group-1"}
|
|
result := p.ValidateGroup(session)
|
|
|
|
assert.Equal(t, false, result)
|
|
}
|
|
|
|
func TestAzureRightPermittedGroups(t *testing.T) {
|
|
p := testAzureProvider("")
|
|
p.SetGroupRestriction([]string{"test-group-1", "test-group-2"})
|
|
|
|
session := &SessionState{
|
|
AccessToken: "imaginary_access_token",
|
|
IDToken: "imaginary_IDToken_token",
|
|
Groups: "no one|cares|test-group-2|non existing|groups"}
|
|
result := p.ValidateGroup(session)
|
|
|
|
assert.Equal(t, true, result)
|
|
}
|
|
|
|
func TestAzureLoginURLnoResource(t *testing.T) {
|
|
p := testAzureProvider("")
|
|
p.ProtectedResource = nil
|
|
|
|
result := p.GetLoginURL("http://redirect/url", "state")
|
|
assert.Equal(t, "?client_id=&nonce=FIXME&prompt=&redirect_uri=http%3A%2F%2Fredirect%2Furl&response_mode=form_post&response_type=id_token+code&scope=openid&state=state", result)
|
|
}
|
|
|
|
func TestAzureLoginURL(t *testing.T) {
|
|
p := testAzureProvider("")
|
|
|
|
result := p.GetLoginURL("http://redirect/url", "state")
|
|
assert.Equal(t, "?client_id=&nonce=FIXME&prompt=&redirect_uri=http%3A%2F%2Fredirect%2Furl&resource=https%3A%2F%2Fgraph.microsoft.com&response_mode=form_post&response_type=id_token+code&scope=openid&state=state", result)
|
|
}
|