2021-01-09 20:39:05 +00:00
|
|
|
package saml
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/crewjam/saml"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"github.com/phuslu/log"
|
2021-01-10 00:35:50 +00:00
|
|
|
"go.sebtobie.de/httpserver/auth"
|
2021-01-09 20:39:05 +00:00
|
|
|
"gopkg.in/dgrijalva/jwt-go.v3"
|
|
|
|
)
|
|
|
|
|
|
|
|
var defaccount = &account{
|
|
|
|
data: map[string]interface{}{
|
2021-01-10 00:35:50 +00:00
|
|
|
auth.AccountID: "",
|
|
|
|
auth.AccountAnon: true,
|
2021-01-09 20:39:05 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
func maptoarray(m map[string]interface{}) (output []interface{}) {
|
|
|
|
for k, v := range m {
|
|
|
|
output = append(output, []interface{}{k, v})
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Account returns the Account representation of the user
|
2021-01-10 00:35:50 +00:00
|
|
|
func (s *SAML) Account(c *gin.Context) auth.Account {
|
2021-01-09 20:39:05 +00:00
|
|
|
acc := &(*defaccount)
|
|
|
|
acc.s = s
|
|
|
|
cookie, err := c.Cookie(s.Cookiename)
|
|
|
|
if err != nil {
|
|
|
|
log.Debug().Err(err).Msg("Cookie error")
|
|
|
|
return acc
|
|
|
|
}
|
|
|
|
var (
|
|
|
|
claim *jwt.MapClaims
|
|
|
|
ok bool
|
|
|
|
)
|
|
|
|
token, err := jwt.ParseWithClaims(cookie, &jwt.MapClaims{}, s.signingkey)
|
|
|
|
if err != nil {
|
|
|
|
log.Debug().Err(err).Msg("Error while parsing token")
|
|
|
|
}
|
|
|
|
if claim, ok = token.Claims.(*jwt.MapClaims); ok && token.Valid {
|
|
|
|
log.Debug().KeysAndValues(claim).Msg("Got valid token")
|
|
|
|
acc.data = *claim
|
|
|
|
return acc
|
|
|
|
}
|
|
|
|
log.Debug().Bool("valid", token.Valid).KeysAndValues(maptoarray(*claim)...).Msg("problem vith token")
|
|
|
|
return acc
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *SAML) signingkey(token *jwt.Token) (key interface{}, err error) {
|
|
|
|
if _, ok := token.Method.(*jwt.SigningMethodRSAPSS); !ok {
|
|
|
|
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
|
|
|
|
}
|
|
|
|
return &s.jwtprivatekey.PublicKey, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type account struct {
|
|
|
|
s *SAML
|
|
|
|
data map[string]interface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *account) Anonymous() bool {
|
2021-01-10 00:35:50 +00:00
|
|
|
return a.data[auth.AccountAnon].(bool)
|
2021-01-09 20:39:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (a *account) Redirect(c *gin.Context) {
|
|
|
|
id := uuid.New().String()
|
|
|
|
tokenstring, err := jwttoken(jwt.MapClaims{
|
2021-01-10 00:35:50 +00:00
|
|
|
auth.AccountID: id,
|
|
|
|
auth.AccountAnon: true,
|
2021-01-09 20:39:05 +00:00
|
|
|
}, a.s.jwtprivatekey)
|
|
|
|
if err != nil {
|
|
|
|
log.Error().Err(err).Msg("Failed to generate the token")
|
|
|
|
c.AbortWithStatus(http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
c.SetCookie(a.s.Cookiename, tokenstring, int(time.Hour), "", "", true, true)
|
|
|
|
request, err := a.s.sp.MakeAuthenticationRequest(a.s.sp.GetSSOBindingLocation(saml.HTTPRedirectBinding))
|
|
|
|
if err != nil {
|
|
|
|
c.AbortWithStatus(http.StatusInternalServerError)
|
|
|
|
}
|
|
|
|
request.ID = id
|
|
|
|
log.Debug().Msgf("Leite weiter: %s", request.Redirect(c.Request.URL.String()).String())
|
|
|
|
c.Redirect(http.StatusSeeOther, request.Redirect(c.Request.URL.String()).String())
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *account) Get(key string) interface{} {
|
|
|
|
return a.data[key]
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *account) List() []string {
|
|
|
|
liste := make([]string, len(a.data))
|
|
|
|
for key := range a.data {
|
|
|
|
liste = append(liste, key)
|
|
|
|
}
|
|
|
|
return liste
|
|
|
|
}
|