improve permissions system

This commit is contained in:
Xavier Henner 2019-07-17 19:12:00 +02:00
parent 0d918b7540
commit e18aa583d0
5 changed files with 90 additions and 36 deletions

View File

@ -26,13 +26,13 @@ type jsonInputParams struct {
}
type HttpServer struct {
Port string
ovpn *OpenVpnMgt
key string
cert string
minProfile string
neededProfile string
certPool *x509.CertPool
Port string
ovpn *OpenVpnMgt
key string
cert string
minProfile string
neededProfiles []string
certPool *x509.CertPool
}
func parseJsonQuery(r *http.Request) (*jsonInput, error) {
@ -119,9 +119,9 @@ func (h *HttpServer) ajaxHandler(w http.ResponseWriter, r *http.Request) {
}
webuser := strings.Replace(r.TLS.PeerCertificates[0].Subject.CommonName, " ", "", -1)
profile, _, _ := h.ovpn.AuthLoop(h.minProfile, webuser, "", false)
if profile != h.neededProfile {
http.Error(w, fmt.Sprintf("You need the %s profile", h.neededProfile), 403)
_, _, _, profilePath := h.ovpn.AuthLoop(h.minProfile, webuser, "", false)
if inArray(h.neededProfiles, profilePath) {
http.Error(w, fmt.Sprintf("You need on of %s profile", h.neededProfiles), 403)
return
}
log.Printf("%s is connected via the web interfaces\n", webuser)
@ -152,14 +152,14 @@ func (h *HttpServer) ajaxHandler(w http.ResponseWriter, r *http.Request) {
return
}
func NewHTTPServer(port, key, cert, ca, minProfile, neededProfile string, s *OpenVpnMgt) {
func NewHTTPServer(port, key, cert, ca, minProfile string, neededProfiles []string, s *OpenVpnMgt) {
h := &HttpServer{
Port: port,
ovpn: s,
key: key,
cert: cert,
minProfile: minProfile,
neededProfile: neededProfile,
Port: port,
ovpn: s,
key: key,
cert: cert,
minProfile: minProfile,
neededProfiles: neededProfiles,
}
http.HandleFunc("/help", h.helpHandler)

20
ldap.go
View File

@ -25,7 +25,7 @@ type ldapConfig struct {
certAuth string
ipMin net.IP
ipMax net.IP
upgradeFrom string
upgradeFrom []string
routes []string
}
@ -46,21 +46,31 @@ func (l *ldapConfig) addIPRange(s string) error {
// auth loop. Try all auth profiles from startProfile
// return the last possible profile and the mail if we found a mail like login
func (s *OpenVpnMgt) AuthLoop(startProfile, user, pass string, overridePwdCheck bool) (string, string, string) {
func (s *OpenVpnMgt) AuthLoop(startProfile, user, pass string, overridePwdCheck bool) (string, string, string, []string) {
login := []string{user}
profile := startProfile
mail := ""
otpSalt := ""
profilePath := []string{}
re := rcache.Get("^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$")
for {
// the first login that match the mail regexp is the mail address
if mail == "" && re.MatchString(login[0]) {
mail = login[0]
}
n := profile
for k, ldap := range s.ldap {
if ldap.upgradeFrom != profile {
// check if the current profile is an upgrade of the previous one
// check the startup profile first
ok := (profile == "") && (len(ldap.upgradeFrom) == 0)
for _, possible := range ldap.upgradeFrom {
if possible == profile {
ok = true
}
}
if !ok {
continue
}
err, userOk, passOk, attributes := ldap.Auth(login, pass)
@ -90,6 +100,8 @@ func (s *OpenVpnMgt) AuthLoop(startProfile, user, pass string, overridePwdCheck
// we have either a positive auth ok a previous valid one
if passOk || profile != "" || overridePwdCheck {
profile = k
profilePath = append(profilePath, profile)
break
}
}
}
@ -100,7 +112,7 @@ func (s *OpenVpnMgt) AuthLoop(startProfile, user, pass string, overridePwdCheck
}
}
return profile, mail, otpSalt
return profile, mail, otpSalt, profilePath
}
// override the real DialTLS function

View File

@ -74,7 +74,7 @@ func main() {
routes: parseConfigArray(config, profile+".routes"),
mfaType: config.GetString(profile+".mfa", ""),
certAuth: config.GetString(profile+".cert", "optionnal"),
upgradeFrom: config.GetString(profile+".upgradeFrom", ""),
upgradeFrom: parseConfigArray(config, profile+".upgradeFrom"),
}
if err := ldapConf.addIPRange(config.GetString(profile+".IPRange", "")); err != nil {
log.Println(err)
@ -97,6 +97,6 @@ func main() {
config.GetString("config.http.cert", ""),
config.GetString("config.http.ca", ""),
config.GetString("config.http.startAuth", "CORP"),
config.GetString("config.http.reqAuth", "ADMINS"),
parseConfigArray(config, "config.http.reqAuth"),
server)
}

View File

@ -2,6 +2,26 @@ config
{
profiles:
{
###################################################################
### Security Model ###
### ###
### +---> CONTRACT ###
### | ###
### start-here +-------> DATACENTER ###
### | | ###
### +---> CORP ------------> DEV -----> ADMINS ###
### | ^ ###
### | | ###
### +--> IT-AND-SEC ---+ ###
### ###
### CORP/IT-AND-SEC have the same IPs but not the web perms ###
### ADMIN/DATACENTER have the same IPs but not the web perms ###
### ###
### attributes[0] must match validGroups ###
### attributes[1] is the login for the next security groups ###
### attributes[2] is used as a salt for mfa generation ###
### ###
###################################################################
CONTRACT:
{
servers: [ "dc-11.office.daily","dc-12.office.daily","dc-13.office.daily" ]
@ -9,13 +29,12 @@ config
bindCn: "CN=VPN Service,OU=Services,OU=Dailymotion,DC=office,DC=daily",
bindPw: "********************",
searchFilter: "(&(sAMAccountName=%s))"
attributes: [ "memberOf", "mail" ]
attributes: [ "memberOf", "mail", "extensionAttribute8" ]
validGroups:
[
"CN=SEC_VPN_Users_External,OU=Security,OU=Groups,OU=Dailymotion,DC=office,DC=daily",
]
mfa: "okta"
cert: "ignore"
mfa: "internal"
IPRange: "192.168.207.1 - 192.168.207.254",
routes:
[
@ -38,15 +57,32 @@ config
bindCn: "CN=VPN Service,OU=Services,OU=Dailymotion,DC=office,DC=daily",
bindPw: "********************",
searchFilter: "(&(sAMAccountName=%s))"
attributes: [ "memberOf", "mail" ]
attributes: [ "memberOf", "mail", "extensionAttribute8" ]
validGroups:
[
"CN=SEC_VPN,OU=Security,OU=Groups,OU=Dailymotion,DC=office,DC=daily",
]
mfa: "okta"
cert: "optionnal"
mfa: ""
IPRange: "192.168.201.1-192.168.203.254"
}
IT-AND-SEC:
{
servers: [ "dc-11.office.daily","dc-12.office.daily","dc-13.office.daily" ]
baseDN: "OU=Dailymotion,DC=office,DC=daily",
bindCn: "CN=VPN Service,OU=Services,OU=Dailymotion,DC=office,DC=daily",
bindPw: "********************",
searchFilter: "(&(mail=%s))"
attributes: [ "memberOf", "mail", "extensionAttribute8" ]
upgradeFrom: [ "CORP" ]
validGroups:
[
"CN=IT-Office,OU=Security,OU=Groups,OU=Dailymotion,DC=office,DC=daily",
"CN=Security,OU=Security,OU=Groups,OU=Dailymotion,DC=office,DC=daily",
]
mfa: ""
IPRange: "192.168.201.1-192.168.203.254"
}
DEV:
{
servers: [ "ldap-auth.vip.dailymotion.com" ]
@ -55,9 +91,8 @@ config
bindPw: "**********"
searchFilter: "(&(mail=%s))"
attributes: [ "description", "sshPublicKey" ]
upgradeFrom: "CORP"
upgradeFrom: [ "CORP", "IT-AND-SEC" ]
mfa: ""
cert: "optionnal"
IPRange: "192.168.204.1-192.168.206.254"
}
ADMINS:
@ -66,11 +101,19 @@ config
[
"infra",
"net",
]
upgradeFrom: [ "DEV" ]
mfa: "internal"
IPRange: "192.168.200.2-192.168.200.254"
}
DATACENTER:
{
validGroups:
[
"datacenter",
]
upgradeFrom: "DEV"
upgradeFrom: [ "DEV" ]
mfa: "internal"
cert: "mandatory"
IPRange: "192.168.200.2-192.168.200.254"
}
}
@ -82,9 +125,8 @@ config
key: "/etc/ssl/private/server-key.pem"
cert: "/etc/ssl/certs/server-bundle.pem"
startAuth: "CORP"
reqAuth: "ADMINS"
reqAuth: [ "ADMINS", "IP-AND-SEC" ]
}
cacheDir: "/var/run/openvpn/"
authCa: "/usr/local/share/ca-certificates/Dailymotion.crt"
masterSecrets: [ "********************************" ]

View File

@ -266,7 +266,7 @@ func (c *vpnSession) auth(s *OpenVpnMgt) (error, int) {
}
otpSalt := ""
c.Profile, c.Mail, otpSalt = s.AuthLoop("", c.Login, c.password, tokenPasswordOk)
c.Profile, c.Mail, otpSalt, _ = s.AuthLoop("", c.Login, c.password, tokenPasswordOk)
// no profile validated, we stop here
if c.Profile == "" {