diff --git a/README.md b/README.md index a62151ab4..3cdcf4d6f 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ Valid providers are : * [GitLab](#gitlab-auth-provider) * [LinkedIn](#linkedin-auth-provider) * [MyUSA](#myusa-auth-provider) +* [Okta](#okta-auth-provider) The provider can be selected using the `provider` configuration value. @@ -139,6 +140,11 @@ For adding an application to the Microsoft Azure AD follow [these steps to add a Take note of your `TenantId` if applicable for your situation. The `TenantId` can be used to override the default `common` authorization server with a tenant specific server. +### Okta Auth Provider + +[Okta](https://www.okta.com/) is a hosted SSO provider. You will need to set the `okta-domain` to your organization's Okta domain. + + ## Email Authentication To authorize by email domain use `--email-domain=yourcompany.com`. To authorize individual email addresses use `--authenticated-emails-file=/path/to/file` with one email per line. To authorize all email addresses use `--email-domain=*`. diff --git a/main.go b/main.go index ab0e4d353..39758a13c 100644 --- a/main.go +++ b/main.go @@ -49,6 +49,7 @@ func main() { flagSet.Var(&googleGroups, "google-group", "restrict logins to members of this google group (may be given multiple times).") flagSet.String("google-admin-email", "", "the google admin to impersonate for api calls") flagSet.String("google-service-account-json", "", "the path to the service account json credentials") + flagSet.String("okta-domain", "", "the full domain for which your organization's okta is configured (example.okta.com)") flagSet.String("client-id", "", "the OAuth Client ID: ie: \"123456.apps.googleusercontent.com\"") flagSet.String("client-secret", "", "the OAuth Client Secret") flagSet.String("authenticated-emails-file", "", "authenticate against emails via file (one per line)") diff --git a/options.go b/options.go index f1df9169b..95ac2e5d9 100644 --- a/options.go +++ b/options.go @@ -35,6 +35,7 @@ type Options struct { GoogleGroups []string `flag:"google-group" cfg:"google_group"` GoogleAdminEmail string `flag:"google-admin-email" cfg:"google_admin_email"` GoogleServiceAccountJSON string `flag:"google-service-account-json" cfg:"google_service_account_json"` + OktaDomain string `flag:"okta-domain" cfg:"okta_domain"` HtpasswdFile string `flag:"htpasswd-file" cfg:"htpasswd_file"` DisplayHtpasswdForm bool `flag:"display-htpasswd-form" cfg:"display_htpasswd_form"` CustomTemplatesDir string `flag:"custom-templates-dir" cfg:"custom_templates_dir"` @@ -252,6 +253,8 @@ func parseProviderInfo(o *Options, msgs []string) []string { p.SetGroupRestriction(o.GoogleGroups, o.GoogleAdminEmail, file) } } + case *providers.OktaProvider: + p.SetOktaDomain(o.OktaDomain) } return msgs } diff --git a/providers/okta.go b/providers/okta.go new file mode 100644 index 000000000..bc9ef8a15 --- /dev/null +++ b/providers/okta.go @@ -0,0 +1,69 @@ +package providers + +import ( + "fmt" + "log" + "net/http" + "net/url" + + "github.com/bitly/oauth2_proxy/api" +) + +type OktaProvider struct { + *ProviderData +} + +func (p *OktaProvider) SetOktaDomain(domain string) { + if p.LoginURL == nil || p.LoginURL.String() == "" { + p.LoginURL = &url.URL{ + Scheme: "https", + Host: domain, + Path: "/oauth2/v1/authorize", + } + } + if p.RedeemURL == nil || p.RedeemURL.String() == "" { + p.RedeemURL = &url.URL{ + Scheme: "https", + Host: domain, + Path: "/oauth2/v1/token", + } + } + if p.ValidateURL == nil || p.ValidateURL.String() == "" { + p.ValidateURL = &url.URL{ + Scheme: "https", + Host: domain, + Path: "/oauth2/v1/userinfo", + } + } +} + +func NewOktaProvider(p *ProviderData) *OktaProvider { + p.ProviderName = "Okta" + if p.Scope == "" { + p.Scope = "openid profile email" + } + return &OktaProvider{ProviderData: p} +} + +func getOktaHeader(access_token string) http.Header { + header := make(http.Header) + header.Set("Authorization", fmt.Sprintf("Bearer %s", access_token)) + return header +} + +func (p *OktaProvider) GetEmailAddress(s *SessionState) (string, error) { + + req, err := http.NewRequest("GET", + p.ValidateURL.String(), nil) + if err != nil { + log.Printf("failed building request %s", err) + return "", err + } + req.Header = getOktaHeader(s.AccessToken) + json, err := api.Request(req) + if err != nil { + log.Printf("failed making request %s", err) + return "", err + } + return json.Get("email").String() +} diff --git a/providers/providers.go b/providers/providers.go index fb2e5fc51..150c3d62d 100644 --- a/providers/providers.go +++ b/providers/providers.go @@ -30,6 +30,8 @@ func New(provider string, p *ProviderData) Provider { return NewAzureProvider(p) case "gitlab": return NewGitLabProvider(p) + case "okta": + return NewOktaProvider(p) default: return NewGoogleProvider(p) }