Remove redundant debug logs. Fix nonce setting. Fix ordering in azure docs.

This commit is contained in:
Lukasz Leszczuk 2019-09-06 16:52:17 +02:00
parent 6b1e5caa40
commit 08bede8f90
8 changed files with 40 additions and 94 deletions

View File

@ -1,6 +1,6 @@
include .env
BINARY := oauth2_proxy
REPOSITORY := quay.io/pusher
REPOSITORY ?= quay.io/pusher
VERSION := $(shell git describe --always --dirty --tags 2>/dev/null || echo "undefined")
.NOTPARALLEL:

View File

@ -67,14 +67,14 @@ Note: The user is checked against the group members list on initial authenticati
### Azure Auth Provider
1. Add an application: go to [https://portal.azure.com](https://portal.azure.com), choose **"Azure Active Directory"** in the left menu, select **"App registrations"** and then click on **"New app registration"**.
1. Pick a name and choose **"Webapp / API"** as application type. Use `https://internal.yourcompany.com` as Sign-on URL. Click **"Create"**.
1. On the **"Overview"** page of the app read `client id (application id)` and `tenant id`
1. On the **"Manage"** / **"Authentication"** page of the app, pick a logo and select **"Multi-tenanted"** if you want to allow users from multiple organizations to access your app. Note down the application ID. Click **"Save"**.
1. On the **"Manage"** / **"Authentication"** page of the app, add `https://internal.yourcompanycom/oauth2/callback` for each host that you want to protect by the oauth2 proxy. Click **"Save"**.
1. On the **"Manage"** / **"API Permissions"** page of the app, click on **"Add a permission"** and then on **"Microsoft Graph"**/**"Delegated permissions"**/**"User"**/**"User.Read"**. Hit **"Add permissions"**.
1. On the **"Manage"** / **"Certificates & secret"** page of the app, add a new client secret, select expiration date and note down the value after hitting **"Add"** (it won't be readable after page reloads).
1. On the **"Manage"** / **"Manifest"** set `groupMembershipClaims` property to `SecurityGroup`
1. Configure the proxy with
2. Pick a name and choose **"Webapp / API"** as application type. Use `https://internal.yourcompany.com` as Sign-on URL. Click **"Create"**.
3. On the **"Overview"** page of the app read `client id (application id)` and `tenant id`
4. On the **"Manage"** / **"Authentication"** page of the app, pick a logo and select **"Multi-tenanted"** if you want to allow users from multiple organizations to access your app. Note down the application ID. Click **"Save"**.
5. On the **"Manage"** / **"Authentication"** page of the app, add `https://internal.yourcompanycom/oauth2/callback` for each host that you want to protect by the oauth2 proxy. Click **"Save"**.
6. On the **"Manage"** / **"API Permissions"** page of the app, click on **"Add a permission"** and then on **"Microsoft Graph"**/**"Delegated permissions"**/**"User"**/**"User.Read"**. Hit **"Add permissions"**.
7. On the **"Manage"** / **"Certificates & secret"** page of the app, add a new client secret, select expiration date and note down the value after hitting **"Add"** (it won't be readable after page reloads).
8. On the **"Manage"** / **"Manifest"** set `groupMembershipClaims` property to `SecurityGroup`
9. Configure the proxy with
```
--provider=azure

View File

@ -338,11 +338,7 @@ func (p *OAuthProxy) redeemCode(host, code string) (s *sessionsapi.SessionState,
return nil, err
}
s.Email = userDetails.Email
if userDetails.UID != "" {
s.ID = userDetails.UID
} else {
s.ID = ""
}
}
if s.User == "" {

View File

@ -69,10 +69,10 @@ type Options struct {
SkipJwtBearerTokens bool `flag:"skip-jwt-bearer-tokens" cfg:"skip_jwt_bearer_tokens" env:"OAUTH2_PROXY_SKIP_JWT_BEARER_TOKENS"`
ExtraJwtIssuers []string `flag:"extra-jwt-issuers" cfg:"extra_jwt_issuers" env:"OAUTH2_PROXY_EXTRA_JWT_ISSUERS"`
PassBasicAuth bool `flag:"pass-basic-auth" cfg:"pass_basic_auth" env:"OAUTH2_PROXY_PASS_BASIC_AUTH"`
PassGroups bool `flag:"pass-groups" cfg:"pass_groups"`
FilterGroups string `flag:"filter-groups" cfg:"filter_groups"`
PermitGroups []string `flag:"permit-groups" cfg:"permit_groups"`
GroupsDelimiter string `flag:"groups-delimiter" cfg:"groups_delimiter"`
PassGroups bool `flag:"pass-groups" cfg:"pass_groups" env:"OAUTH2_PROXY_PASS_GROUPS"`
FilterGroups string `flag:"filter-groups" cfg:"filter_groups" env:"OAUTH2_PROXY_FILTER_GROUPS"`
PermitGroups []string `flag:"permit-groups" cfg:"permit_groups" env:"OAUTH2_PROXY_PERMIT_GROUPS"`
GroupsDelimiter string `flag:"groups-delimiter" cfg:"groups_delimiter" env:"OAUTH2_PROXY_GROUPS_DELIMITER"`
PermitUsers []string `flag:"permit-users" cfg:"permit_users"`
BasicAuthPassword string `flag:"basic-auth-password" cfg:"basic_auth_password" env:"OAUTH2_PROXY_BASIC_AUTH_PASSWORD"`
PassAccessToken bool `flag:"pass-access-token" cfg:"pass_access_token" env:"OAUTH2_PROXY_PASS_ACCESS_TOKEN"`
@ -168,7 +168,6 @@ func NewOptions() *Options {
FilterGroups: "",
GroupsDelimiter: "|",
PermitGroups: []string{},
PermitUsers: []string{},
PassAccessToken: false,
PassHostHeader: true,
SetAuthorization: false,
@ -409,7 +408,6 @@ func parseProviderInfo(o *Options, msgs []string) []string {
switch p := o.provider.(type) {
case *providers.AzureProvider:
p.Configure(o.AzureTenant)
logger.Printf("PermitGroups %+v\n", splittedGroups)
if len(splittedGroups) > 0 {
p.SetGroupRestriction(splittedGroups)
}

View File

@ -47,8 +47,6 @@ func NewAzureProvider(p *ProviderData) *AzureProvider {
if p.ApprovalPrompt == "force" {
p.ApprovalPrompt = "consent"
}
logger.Printf("Approval prompt: '%s'", p.ApprovalPrompt)
return &AzureProvider{ProviderData: p}
}
@ -115,7 +113,6 @@ func getUserIDFromJSON(json *simplejson.Json) (string, error) {
if err != nil {
return "", err
}
return uid, err
}
@ -132,32 +129,20 @@ func (p *AzureProvider) GetUserDetails(s *sessions.SessionState) (*UserDetails,
req.Header = getAzureHeader(s.AccessToken)
json, err := requests.Request(req)
if err != nil {
return nil, err
}
logger.Printf(" JSON: %v", json)
for key, value := range json.Interface().(map[string]interface{}) {
logger.Printf("\t %20v : %v", key, value)
}
email, err := getEmailFromJSON(json)
if err != nil {
logger.Printf("[GetUserDetails] failed making request: %s", err)
return nil, err
}
uid, err := getUserIDFromJSON(json)
if err != nil {
logger.Printf("[GetUserDetails] failed to get User ID: %s", err)
}
uid, _ := getUserIDFromJSON(json)
if email == "" {
logger.Printf("failed to get email address")
return nil, errors.New("Client email not found")
}
logger.Printf("[GetUserDetails] Chosen email address: '%s'", email)
return &UserDetails{
Email: email,
UID: uid,
@ -192,10 +177,8 @@ func (p *AzureProvider) GetGroups(s *sessions.SessionState, f string) (map[strin
// ValidateExemptions checks if we can allow user login dispite group membership returned failure
func (p *AzureProvider) ValidateExemptions(s *sessions.SessionState) (bool, string) {
logger.Printf("ValidateExemptions: validating for %v : %v", s.Email, s.ID)
for eAccount, eGroup := range p.ExemptedUsers {
if eAccount == s.Email || eAccount == s.Email+":"+s.ID {
logger.Printf("ValidateExemptions: \t found '%v' user in exemption list. Returning '%v' group membership", eAccount, eGroup)
return true, eGroup
}
}
@ -213,7 +196,7 @@ func (p *AzureProvider) GetLoginURL(redirectURI, state string) string {
params.Add("scope", p.Scope)
params.Add("state", state)
params.Set("prompt", p.ApprovalPrompt)
params.Set("nonce", "FIXME")
params.Set("nonce", randSeq(32))
if p.ProtectedResource != nil && p.ProtectedResource.String() != "" {
params.Add("resource", p.ProtectedResource.String())
}
@ -230,25 +213,16 @@ func (p *AzureProvider) SetGroupRestriction(groups []string) {
if len(groups) == 0 {
return
}
logger.Printf("Set group restrictions. Allowed groups are:")
logger.Printf("\t *GROUP NAME* : *GROUP ID*")
for _, pGroup := range groups {
splittedGroup := strings.Split(pGroup, ":")
var groupName string
var groupID string
if len(splittedGroup) == 1 {
groupName, groupID = splittedGroup[0], ""
p.PermittedGroups[splittedGroup[0]] = ""
} else if len(splittedGroup) > 2 {
logger.Fatalf("failed to parse '%v'. Too many ':' separators", pGroup)
} else {
groupName, groupID = splittedGroup[0], splittedGroup[1]
} else if len(splittedGroup) == 2 {
p.PermittedGroups[splittedGroup[0]] = splittedGroup[1]
} else {
logger.Printf("Warning: failed to parse '%v'. Too many ':' separators", pGroup)
}
logger.Printf("\t - %-30s %s", groupName, groupID)
}
logger.Printf("")
}
func (p *AzureProvider) SetGroupsExemption(exemptions []string) {
@ -262,8 +236,6 @@ func (p *AzureProvider) SetGroupsExemption(exemptions []string) {
var userRecord string
var groupName string
logger.Printf("Configure user exemption list:")
logger.Printf("\t *USER NAME*:*USER ID* : *DEFAULT GROUP*")
for _, pRecord := range exemptions {
splittedRecord := strings.Split(pRecord, ":")
@ -271,31 +243,25 @@ func (p *AzureProvider) SetGroupsExemption(exemptions []string) {
userRecord, groupName = splittedRecord[0], ""
} else if len(splittedRecord) == 2 {
userRecord, groupName = splittedRecord[0], splittedRecord[1]
} else if len(splittedRecord) > 3 {
logger.Fatalf("failed to parse '%v'. Too many ':' separators", pRecord)
} else {
userRecord = splittedRecord[0] + ":" + splittedRecord[1]
groupName = splittedRecord[2]
}
p.ExemptedUsers[userRecord] = groupName
logger.Printf("\t - %-65s %s", userRecord, groupName)
}
logger.Printf("")
}
func (p *AzureProvider) ValidateGroupWithSession(s *sessions.SessionState) bool {
if len(p.PermittedGroups) != 0 {
for groupName, groupID := range p.PermittedGroups {
logger.Printf("ValidateGroup: %v", groupName)
if len(p.PermittedGroups) == 0 {
return true
}
for _, groupID := range p.PermittedGroups {
if strings.Contains(s.Groups, groupID) {
return true
}
}
logger.Printf("Returning False from ValidateGroup")
return false
}
return true
}
func (p *AzureProvider) GroupPermitted(gName *string, gID *string) bool {
// Validate provided group
@ -306,15 +272,11 @@ func (p *AzureProvider) GroupPermitted(gName *string, gID *string) bool {
if len(p.PermittedGroups) != 0 {
for pGroupName, pGroupID := range p.PermittedGroups {
if pGroupName == *gName {
logger.Printf("ValidateGroup: %v : %v", pGroupName, pGroupID)
if pGroupID == "" || gID == nil {
logger.Printf("ValidateGroup: %v : %v : no Group ID defined for permitted group. Approving", pGroupName, pGroupID)
return true
} else if pGroupID == *gID {
logger.Printf("ValidateGroup: %v : %v : Group ID matches defined in permitted group. Approving", pGroupName, pGroupID)
return true
}
logger.Printf("ValidateGroup: %v : %v != %v Group IDs didn't match", pGroupName, pGroupID, *gID)
}
}
return false

View File

@ -13,16 +13,6 @@ type NotImplementedError struct {
message string
}
func NewNotImplementedError(message string) *NotImplementedError {
return &NotImplementedError{
message: "Not implemented: " + message,
}
}
func (e *NotImplementedError) Error() string {
return e.message
}
// stripToken is a helper function to obfuscate "access_token"
// query parameters
func stripToken(endpoint string) string {

View File

@ -7,7 +7,6 @@ import (
"errors"
"fmt"
"io/ioutil"
"math/rand"
"net/http"
"net/url"
"time"
@ -29,17 +28,6 @@ type LoginGovProvider struct {
PubJWKURL *url.URL
}
// For generating a nonce
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
func randSeq(n int) string {
b := make([]rune, n)
for i := range b {
b[i] = letters[rand.Intn(len(letters))]
}
return string(b)
}
// NewLoginGovProvider initiates a new LoginGovProvider
func NewLoginGovProvider(p *ProviderData) *LoginGovProvider {
p.ProviderName = "login.gov"

View File

@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"io/ioutil"
"math/rand"
"net/http"
"net/url"
"time"
@ -95,6 +96,17 @@ func (p *ProviderData) GetLoginURL(redirectURI, state string) string {
return a.String()
}
// For generating a nonce
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
func randSeq(n int) string {
b := make([]rune, n)
for i := range b {
b[i] = letters[rand.Intn(len(letters))]
}
return string(b)
}
// CookieForSession serializes a session state for storage in a cookie
func (p *ProviderData) CookieForSession(s *sessions.SessionState, c *encryption.Cipher) (string, error) {
return s.EncodeSessionState(c)
@ -111,7 +123,7 @@ func (p *ProviderData) GetEmailAddress(s *sessions.SessionState) (string, error)
}
func (p *ProviderData) GetUserDetails(s *sessions.SessionState) (*UserDetails, error) {
return nil, NewNotImplementedError("")
return nil, errors.New("not implemented")
}
// GetUserName returns the Account username