Add fallback authentication through Kerberos
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
4c46386fff
commit
9807eeec1a
11
auth.go
11
auth.go
@ -9,8 +9,19 @@ import (
|
|||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var LocalAuthFunc = checkAuthKrb5
|
||||||
|
var localAuthUsers arrayFlags
|
||||||
|
|
||||||
|
type loginForm struct {
|
||||||
|
Login string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
router.GET("/api/auth", apiAuthHandler(validateAuthToken))
|
router.GET("/api/auth", apiAuthHandler(validateAuthToken))
|
||||||
|
router.POST("/api/auth", apiRawHandler(func(w http.ResponseWriter, ps httprouter.Params, body []byte) HTTPResponse {
|
||||||
|
return formatApiResponse(LocalAuthFunc(w, ps, body))
|
||||||
|
}))
|
||||||
router.POST("/api/auth/logout", apiRawHandler(logout))
|
router.POST("/api/auth/logout", apiRawHandler(logout))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
78
auth_krb5.go
Normal file
78
auth_krb5.go
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gokrb5/v8/client"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/config"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/etypeID"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/krberror"
|
||||||
|
"github.com/julienschmidt/httprouter"
|
||||||
|
)
|
||||||
|
|
||||||
|
func parseETypes(s []string, w bool) []int32 {
|
||||||
|
var eti []int32
|
||||||
|
for _, et := range s {
|
||||||
|
if !w {
|
||||||
|
var weak bool
|
||||||
|
for _, wet := range strings.Fields(config.WeakETypeList) {
|
||||||
|
if et == wet {
|
||||||
|
weak = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if weak {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i := etypeID.EtypeSupported(et)
|
||||||
|
if i != 0 {
|
||||||
|
eti = append(eti, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return eti
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkAuthKrb5(w http.ResponseWriter, _ httprouter.Params, body []byte) (interface{}, error) {
|
||||||
|
var lf loginForm
|
||||||
|
if err := json.Unmarshal(body, &lf); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
found := false
|
||||||
|
for _, u := range localAuthUsers {
|
||||||
|
if lf.Login == u {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
return nil, fmt.Errorf("You are not allowed to log you in this way. Please use OpenID Connect.")
|
||||||
|
}
|
||||||
|
|
||||||
|
cnf := config.New()
|
||||||
|
cnf.LibDefaults.DNSLookupKDC = true
|
||||||
|
cnf.LibDefaults.DNSLookupRealm = true
|
||||||
|
cnf.LibDefaults.DefaultTGSEnctypeIDs = parseETypes(cnf.LibDefaults.DefaultTGSEnctypes, cnf.LibDefaults.AllowWeakCrypto)
|
||||||
|
cnf.LibDefaults.DefaultTktEnctypeIDs = parseETypes(cnf.LibDefaults.DefaultTktEnctypes, cnf.LibDefaults.AllowWeakCrypto)
|
||||||
|
cnf.LibDefaults.PermittedEnctypeIDs = parseETypes(cnf.LibDefaults.PermittedEnctypes, cnf.LibDefaults.AllowWeakCrypto)
|
||||||
|
|
||||||
|
c := client.NewWithPassword(lf.Login, "CRI.EPITA.FR", lf.Password, cnf)
|
||||||
|
if err := c.Login(); err != nil {
|
||||||
|
if errk, ok := err.(krberror.Krberror); ok {
|
||||||
|
if errk.RootCause == krberror.NetworkingError {
|
||||||
|
return nil, errors.New(`{"status": "Authentication system unavailable, please retry."}`)
|
||||||
|
} else if errk.RootCause == krberror.KDCError {
|
||||||
|
return nil, errors.New(`{"status": "Invalid username or password"}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
return dummyAuth(w, nil, body)
|
||||||
|
}
|
||||||
|
}
|
16
flag.go
Normal file
16
flag.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type arrayFlags []string
|
||||||
|
|
||||||
|
func (i *arrayFlags) String() string {
|
||||||
|
return fmt.Sprintf("%v", *i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *arrayFlags) Set(value string) error {
|
||||||
|
*i = append(*i, value)
|
||||||
|
return nil
|
||||||
|
}
|
1
go.mod
1
go.mod
@ -6,6 +6,7 @@ require (
|
|||||||
github.com/coreos/go-oidc v2.2.1+incompatible
|
github.com/coreos/go-oidc v2.2.1+incompatible
|
||||||
github.com/go-sql-driver/mysql v1.6.0
|
github.com/go-sql-driver/mysql v1.6.0
|
||||||
github.com/golang/protobuf v1.5.2 // indirect
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
|
github.com/jcmturner/gokrb5/v8 v8.4.2
|
||||||
github.com/julienschmidt/httprouter v1.3.0
|
github.com/julienschmidt/httprouter v1.3.0
|
||||||
github.com/pquerna/cachecontrol v0.1.0 // indirect
|
github.com/pquerna/cachecontrol v0.1.0 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0
|
github.com/russross/blackfriday/v2 v2.1.0
|
||||||
|
16
go.sum
16
go.sum
@ -102,9 +102,24 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
|
|||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
|
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||||
|
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
|
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
|
||||||
|
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
|
||||||
|
github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
|
||||||
|
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
|
||||||
|
github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8=
|
||||||
|
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
|
||||||
|
github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
|
||||||
|
github.com/jcmturner/gokrb5/v8 v8.4.2 h1:6ZIM6b/JJN0X8UM43ZOM6Z4SJzla+a/u7scXFJzodkA=
|
||||||
|
github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc=
|
||||||
|
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
|
||||||
|
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
|
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
|
||||||
@ -140,6 +155,7 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
|
|||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20201112155050-0c6587e931a9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc=
|
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc=
|
||||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
@ -259,8 +259,12 @@ angular.module("AtsebaytApp")
|
|||||||
$location.url("/");
|
$location.url("/");
|
||||||
}, function(response) {
|
}, function(response) {
|
||||||
$scope.pleaseWait = false;
|
$scope.pleaseWait = false;
|
||||||
if (response.data && response.data.errmsg)
|
if (response.data)
|
||||||
alert(response.data.errmsg);
|
$scope.addToast({
|
||||||
|
variant: "danger",
|
||||||
|
title: "Connexion impossible",
|
||||||
|
msg: (response.data ? response.data.errmsg : "Impossible de contacter le serveur"),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -3,13 +3,13 @@
|
|||||||
<h2>Accès à votre compte</h2>
|
<h2>Accès à votre compte</h2>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="login">CRI login</label>
|
<label for="login">CRI login</label>
|
||||||
<input class="form-control" id="login" ng-model="auth.username" placeholder="Entrer votre login" autofocus disabled>
|
<input class="form-control" id="login" ng-model="auth.username" placeholder="Entrer votre login" autofocus>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="password">Mot de passe</label>
|
<label for="password">Mot de passe</label>
|
||||||
<input type="password" class="form-control" id="password" ng-model="auth.password" placeholder="Mot de passe" disabled>
|
<input type="password" class="form-control" id="password" ng-model="auth.password" placeholder="Mot de passe">
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-secondary disabled" disabled>
|
<button type="submit" class="btn btn-secondary">
|
||||||
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true" ng-show="pleaseWait"></span>
|
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true" ng-show="pleaseWait"></span>
|
||||||
Me connecter
|
Me connecter
|
||||||
</button>
|
</button>
|
||||||
|
1
main.go
1
main.go
@ -61,6 +61,7 @@ func main() {
|
|||||||
var dsn = flag.String("dsn", DSNGenerator(), "DSN to connect to the MySQL server")
|
var dsn = flag.String("dsn", DSNGenerator(), "DSN to connect to the MySQL server")
|
||||||
flag.StringVar(&baseURL, "baseurl", baseURL, "URL prepended to each URL")
|
flag.StringVar(&baseURL, "baseurl", baseURL, "URL prepended to each URL")
|
||||||
flag.UintVar(¤tPromo, "current-promo", currentPromo, "Year of the current promotion")
|
flag.UintVar(¤tPromo, "current-promo", currentPromo, "Year of the current promotion")
|
||||||
|
flag.Var(&localAuthUsers, "local-auth-user", "Allow local authentication for this user (bypass OIDC).")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
// Sanitize options
|
// Sanitize options
|
||||||
|
Reference in New Issue
Block a user