package saml import ( "fmt" "net/http" "time" "github.com/crewjam/saml" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v4" "github.com/google/uuid" "github.com/rs/zerolog/log" "go.sebtobie.de/httpserver/auth" "go.sebtobie.de/httpserver/constants" ) var ( defaccount = &account{ data: map[constants.AccountConstant]any{ constants.AccountID: uuid.Nil, constants.AccountAnon: true, }, } _ auth.AuthenticationHandler = &SAML{} ) func maptoarray(m map[string]any) (output []any) { for k, v := range m { output = append(output, []any{k, v}) } return } // Account returns the Account representation of the user func (s *SAML) Account(c *gin.Context) auth.Account { acc := &(*defaccount) acc.s = s cookie, err := c.Cookie(s.Cookiename) if err != nil { 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().Interface("claim", claim).Msg("Got valid token") for key, value := range *claim { acc.data[constants.AccountConstant(key)] = value } return acc } log.Debug().Bool("valid", token.Valid).Interface("claim", claim).Msg("problem vith token") return acc } func (s *SAML) signingkey(token *jwt.Token) (key any, 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[constants.AccountConstant]any } func (a *account) Anonymous() bool { return a.data[constants.AccountAnon].(bool) } func (a *account) Redirect(c *gin.Context) { id := uuid.New().String() tokenstring, err := jwttoken(jwt.MapClaims{ string(constants.AccountID): id, string(constants.AccountAnon): true, }, 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), saml.HTTPRedirectBinding, saml.HTTPRedirectBinding, ) if err != nil { c.AbortWithStatus(http.StatusInternalServerError) } request.ID = id u, err := request.Redirect(c.Request.URL.String(), a.s.sp) if err != nil { log.Error().Err(err).Msg("Failed to create redirect") c.AbortWithStatus(500) return } log.Debug().Msgf("Leite weiter: %s", u.String()) c.Redirect(http.StatusSeeOther, u.String()) } func (a *account) Get(key constants.AccountConstant) any { return a.data[key] } func (a *account) List() []constants.AccountConstant { var liste []constants.AccountConstant for key := range a.data { liste = append(liste, key) } return liste }