Redirect to external login form
This commit is contained in:
parent
4f1b20e392
commit
15fea62a0c
24
api/auth.go
24
api/auth.go
|
@ -127,6 +127,18 @@ func retrieveSessionFromClaims(claims *UserClaims, user *happydns.User, session_
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func requireLogin(opts *config.Options, c *gin.Context, msg string) {
|
||||||
|
if opts.ExternalAuth.URL != nil {
|
||||||
|
customurl := *opts.ExternalAuth.URL
|
||||||
|
q := customurl.Query()
|
||||||
|
q.Set("errmsg", msg)
|
||||||
|
customurl.RawQuery = q.Encode()
|
||||||
|
c.Header("Location", customurl.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"errmsg": msg})
|
||||||
|
}
|
||||||
|
|
||||||
func authMiddleware(opts *config.Options, optional bool) gin.HandlerFunc {
|
func authMiddleware(opts *config.Options, optional bool) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
var token string
|
var token string
|
||||||
|
@ -143,7 +155,7 @@ func authMiddleware(opts *config.Options, optional bool) gin.HandlerFunc {
|
||||||
if optional {
|
if optional {
|
||||||
c.Next()
|
c.Next()
|
||||||
} else {
|
} else {
|
||||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"errmsg": "No authorization token found in cookie nor in Authorization header."})
|
requireLogin(opts, c, "No authorization token found in cookie nor in Authorization header.")
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -157,7 +169,7 @@ func authMiddleware(opts *config.Options, optional bool) gin.HandlerFunc {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("%s provide a bad JWT claims: %s", c.ClientIP(), err.Error())
|
log.Printf("%s provide a bad JWT claims: %s", c.ClientIP(), err.Error())
|
||||||
c.SetCookie(COOKIE_NAME, "", -1, opts.BaseURL+"/", "", opts.DevProxy == "", true)
|
c.SetCookie(COOKIE_NAME, "", -1, opts.BaseURL+"/", "", opts.DevProxy == "", true)
|
||||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"errmsg": fmt.Sprintf("Something goes wrong with your session. Please reconnect.")})
|
requireLogin(opts, c, "Something goes wrong with your session. Please reconnect.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,14 +177,14 @@ func authMiddleware(opts *config.Options, optional bool) gin.HandlerFunc {
|
||||||
if len(claims.Profile.UserId) == 0 {
|
if len(claims.Profile.UserId) == 0 {
|
||||||
log.Printf("%s: no UserId found in JWT claims", c.ClientIP())
|
log.Printf("%s: no UserId found in JWT claims", c.ClientIP())
|
||||||
c.SetCookie(COOKIE_NAME, "", -1, opts.BaseURL+"/", "", opts.DevProxy == "", true)
|
c.SetCookie(COOKIE_NAME, "", -1, opts.BaseURL+"/", "", opts.DevProxy == "", true)
|
||||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"errmsg": fmt.Sprintf("Something goes wrong with your session. Please reconnect.")})
|
requireLogin(opts, c, "Something goes wrong with your session. Please reconnect.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if claims.Profile.Email == "" {
|
if claims.Profile.Email == "" {
|
||||||
log.Printf("%s: no Email found in JWT claims", c.ClientIP())
|
log.Printf("%s: no Email found in JWT claims", c.ClientIP())
|
||||||
c.SetCookie(COOKIE_NAME, "", -1, opts.BaseURL+"/", "", opts.DevProxy == "", true)
|
c.SetCookie(COOKIE_NAME, "", -1, opts.BaseURL+"/", "", opts.DevProxy == "", true)
|
||||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"errmsg": fmt.Sprintf("Something goes wrong with your session. Please reconnect.")})
|
requireLogin(opts, c, "Something goes wrong with your session. Please reconnect.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,7 +193,7 @@ func authMiddleware(opts *config.Options, optional bool) gin.HandlerFunc {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("%s %s", c.ClientIP(), err.Error())
|
log.Printf("%s %s", c.ClientIP(), err.Error())
|
||||||
c.SetCookie(COOKIE_NAME, "", -1, opts.BaseURL+"/", "", opts.DevProxy == "", true)
|
c.SetCookie(COOKIE_NAME, "", -1, opts.BaseURL+"/", "", opts.DevProxy == "", true)
|
||||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"errmsg": fmt.Sprintf("Something goes wrong with your session. Please reconnect.")})
|
requireLogin(opts, c, "Something goes wrong with your session. Please reconnect.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,7 +205,7 @@ func authMiddleware(opts *config.Options, optional bool) gin.HandlerFunc {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("%s %s", c.ClientIP(), err.Error())
|
log.Printf("%s %s", c.ClientIP(), err.Error())
|
||||||
c.SetCookie(COOKIE_NAME, "", -1, opts.BaseURL+"/", "", opts.DevProxy == "", true)
|
c.SetCookie(COOKIE_NAME, "", -1, opts.BaseURL+"/", "", opts.DevProxy == "", true)
|
||||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"errmsg": fmt.Sprintf("Your session has expired. Please reconnect.")})
|
requireLogin(opts, c, "Your session has expired. Please reconnect.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,7 @@ func displayAuthToken(c *gin.Context) {
|
||||||
|
|
||||||
func displayNotAuthToken(opts *config.Options, c *gin.Context) {
|
func displayNotAuthToken(opts *config.Options, c *gin.Context) {
|
||||||
if !opts.NoAuth {
|
if !opts.NoAuth {
|
||||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"errmsg": "Authorization required"})
|
requireLogin(opts, c, "Authorization required")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ func (o *Options) declareFlags() {
|
||||||
flag.Var(&o.StorageEngine, "storage-engine", fmt.Sprintf("Select the storage engine between %v", storage.GetStorageEngines()))
|
flag.Var(&o.StorageEngine, "storage-engine", fmt.Sprintf("Select the storage engine between %v", storage.GetStorageEngines()))
|
||||||
flag.BoolVar(&o.NoAuth, "no-auth", false, "Disable user access control, use default account")
|
flag.BoolVar(&o.NoAuth, "no-auth", false, "Disable user access control, use default account")
|
||||||
flag.Var(&o.JWTSecretKey, "jwt-secret-key", "Secret key used to verify JWT authentication tokens (a random secret is used if undefined)")
|
flag.Var(&o.JWTSecretKey, "jwt-secret-key", "Secret key used to verify JWT authentication tokens (a random secret is used if undefined)")
|
||||||
|
flag.Var(&o.ExternalAuth, "external-auth", "Base URL to use for login and registration (use embedded forms if left empty)")
|
||||||
|
|
||||||
// Others flags are declared in some other files likes sources, storages, ... when they need specials configurations
|
// Others flags are declared in some other files likes sources, storages, ... when they need specials configurations
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,9 @@ type Options struct {
|
||||||
// NoAuth controls if there is user access control or not.
|
// NoAuth controls if there is user access control or not.
|
||||||
NoAuth bool
|
NoAuth bool
|
||||||
|
|
||||||
|
// ExternalAuth is the URL of the login form to use instead of the embedded one.
|
||||||
|
ExternalAuth URL
|
||||||
|
|
||||||
// JWTSecretKey stores the private key to sign and verify JWT tokens.
|
// JWTSecretKey stores the private key to sign and verify JWT tokens.
|
||||||
JWTSecretKey JWTSecretKey
|
JWTSecretKey JWTSecretKey
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ package config // import "happydns.org/config"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"net/url"
|
||||||
)
|
)
|
||||||
|
|
||||||
type JWTSecretKey []byte
|
type JWTSecretKey []byte
|
||||||
|
@ -50,3 +51,25 @@ func (i *JWTSecretKey) Set(value string) error {
|
||||||
*i = z
|
*i = z
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type URL struct {
|
||||||
|
URL *url.URL
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *URL) String() string {
|
||||||
|
if i.URL != nil {
|
||||||
|
return i.URL.String()
|
||||||
|
} else {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *URL) Set(value string) error {
|
||||||
|
u, err := url.Parse(value)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
i.URL = u
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -32,10 +32,21 @@
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
return axios.create({
|
const a = axios.create({
|
||||||
headers: {
|
headers: {
|
||||||
Accept: 'application/json',
|
Accept: 'application/json',
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
a.interceptors.response.use((response) => {
|
||||||
|
return response
|
||||||
|
}, (error) => {
|
||||||
|
if (error.response && error.response.status === 401 && error.response.headers && error.response.headers.location) {
|
||||||
|
window.location = error.response.headers.location
|
||||||
|
}
|
||||||
|
return Promise.reject(error)
|
||||||
|
})
|
||||||
|
|
||||||
|
return a
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user