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:
parent
0e511023f0
commit
416af9eed8
3 changed files with 47 additions and 17 deletions
20
README.md
20
README.md
|
@ -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!)
|
||||||
|
|
|
@ -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
|
||||||
|
|
42
mfa_duo.go
42
mfa_duo.go
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue