1
0
Fork 0
mirror of https://github.com/Luzifer/nginx-sso.git synced 2024-12-20 12:51:17 +00:00

Duo MFA, clean up & documentation

This commit is contained in:
Ben Edmunds 2018-12-28 19:35:26 +00:00
parent 0e511023f0
commit 416af9eed8
3 changed files with 47 additions and 17 deletions

View file

@ -188,6 +188,26 @@ attributes:
<mapping of attributes> <mapping of attributes>
``` ```
#### Duo
This provider needs a configuration to function correctly:
```yaml
mfa:
duo:
# Get your ikey / skey / host from https://duo.com/docs/duoweb#first-steps
ikey: "<IKEY>"
skey: "<SKEY>"
host: "<API HOST>"
user_agent: "nginx-sso"
```
The corresponding expected MFA configuration is as following:
```yaml
provider: duo
```
#### Google Authenticator #### Google Authenticator
The provider name here is `google` while the only supported argument at the moment is `secret`. The secret is what you need to provide to your users for them to add the config to their authenticator. (It MUST be base32 encoded!) The provider name here is `google` while the only supported argument at the moment is `secret`. The secret is what you need to provide to your users for them to add the config to their authenticator. (It MUST be base32 encoded!)

View file

@ -47,7 +47,7 @@ mfa:
ikey: "IKEY" ikey: "IKEY"
skey: "SKEY" skey: "SKEY"
host: "HOST" host: "HOST"
userAgent: "nginx-sso" user_agent: "nginx-sso"
providers: providers:
# Authentication against an Atlassian Crowd directory server # Authentication against an Atlassian Crowd directory server

View file

@ -2,22 +2,27 @@ package main
import ( import (
"net/http" "net/http"
"time"
"strings" "strings"
"time"
"github.com/duosecurity/duo_api_golang" "github.com/duosecurity/duo_api_golang"
"github.com/duosecurity/duo_api_golang/authapi" "github.com/duosecurity/duo_api_golang/authapi"
"github.com/pkg/errors"
yaml "gopkg.in/yaml.v2" yaml "gopkg.in/yaml.v2"
) )
const mfaDuoResponseAllow = "allow"
const mfaDuoRequestTimeout = 10 * time.Second
func init() { func init() {
registerMFAProvider(&mfaDuo{}) registerMFAProvider(&mfaDuo{})
} }
type mfaDuo struct{ type mfaDuo struct {
Ikey string `yaml:"ikey"` IKey string `yaml:"ikey"`
Skey string `yaml:"skey"` SKey string `yaml:"skey"`
Host string `yaml:"host"` Host string `yaml:"host"`
UserAgent string `yaml:"userAgent"` UserAgent string `yaml:"user_agent"`
} }
// ProviderID needs to return an unique string to identify // ProviderID needs to return an unique string to identify
@ -43,8 +48,8 @@ func (m *mfaDuo) Configure(yamlSource []byte) (err error) {
return errProviderUnconfigured return errProviderUnconfigured
} }
m.Ikey = envelope.MFA.Duo.Ikey m.IKey = envelope.MFA.Duo.IKey
m.Skey = envelope.MFA.Duo.Skey m.SKey = envelope.MFA.Duo.SKey
m.Host = envelope.MFA.Duo.Host m.Host = envelope.MFA.Duo.Host
m.UserAgent = envelope.MFA.Duo.UserAgent m.UserAgent = envelope.MFA.Duo.UserAgent
return nil return nil
@ -59,22 +64,28 @@ func (m mfaDuo) ValidateMFA(res http.ResponseWriter, r *http.Request, user strin
if c.Provider != m.ProviderID() { if c.Provider != m.ProviderID() {
continue continue
} }
ip := r.Header.Get("X-Real-IP") remoteIP := r.Header.Get("X-Real-IP")
duo := authapi.NewAuthApi(*duoapi.NewDuoApi(m.Ikey,m.Skey,m.Host,m.UserAgent,duoapi.SetTimeout(10*time.Second))) duo := authapi.NewAuthApi(*duoapi.NewDuoApi(m.IKey, m.SKey, m.Host, m.UserAgent, duoapi.SetTimeout((mfaDuoRequestTimeout))))
for key, values := range r.Form { for key, values := range r.Form {
if strings.HasSuffix(key, mfaLoginFieldName) && len(values[0]) > 0 { if strings.HasSuffix(key, mfaLoginFieldName) && len(values[0]) > 0 {
keyInput = values[0] keyInput = values[0]
} }
} }
//Check if MFA token provided and fallover to push if not supplied //Check if MFA token provided and fallover to push if not supplied
if keyInput != ""{ if keyInput != "" {
auth, _ := duo.Auth("passcode",authapi.AuthUsername(user),authapi.AuthPasscode(keyInput),authapi.AuthIpAddr(ip)) auth, err := duo.Auth("passcode", authapi.AuthUsername(user), authapi.AuthPasscode(keyInput), authapi.AuthIpAddr(remoteIP))
if auth.Response.Result == "allow" { if err != nil {
return errors.Wrap(err, "Unable to authenticate with Duo.")
}
if auth.Response.Result == mfaDuoResponseAllow {
return nil return nil
} }
} else { } else {
auth, _ := duo.Auth("auto",authapi.AuthUsername(user),authapi.AuthDevice("auto"),authapi.AuthIpAddr(ip)) auth, err := duo.Auth("auto", authapi.AuthUsername(user), authapi.AuthDevice("auto"), authapi.AuthIpAddr(remoteIP))
if auth.Response.Result == "allow" { if err != nil {
return errors.Wrap(err, "Unable to authenticate with Duo.")
}
if auth.Response.Result == mfaDuoResponseAllow {
return nil return nil
} }
} }
@ -83,4 +94,3 @@ func (m mfaDuo) ValidateMFA(res http.ResponseWriter, r *http.Request, user strin
// Report this provider was not able to verify the MFA request // Report this provider was not able to verify the MFA request
return errNoValidUserFound return errNoValidUserFound
} }