mirror of
https://github.com/1f349/lavender.git
synced 2024-12-22 15:44:07 +00:00
Add reloading config
This commit is contained in:
parent
54463008f9
commit
41db9d605c
@ -44,34 +44,24 @@ func (s *serveCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{})
|
|||||||
return subcommands.ExitUsageError
|
return subcommands.ExitUsageError
|
||||||
}
|
}
|
||||||
|
|
||||||
openConf, err := os.Open(s.configPath)
|
var conf server.Conf
|
||||||
|
err := loadConfig(s.configPath, &conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
log.Println("[Lavender] Error: missing config file")
|
log.Println("[Lavender] Error: missing config file")
|
||||||
} else {
|
} else {
|
||||||
log.Println("[Lavender] Error: open config file: ", err)
|
log.Println("[Lavender] Error: loading config file: ", err)
|
||||||
}
|
}
|
||||||
return subcommands.ExitFailure
|
return subcommands.ExitFailure
|
||||||
}
|
}
|
||||||
|
|
||||||
var config server.Conf
|
|
||||||
err = json.NewDecoder(openConf).Decode(&config)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("[Lavender] Error: invalid config file: ", err)
|
|
||||||
return subcommands.ExitFailure
|
|
||||||
}
|
|
||||||
|
|
||||||
configPathAbs, err := filepath.Abs(s.configPath)
|
configPathAbs, err := filepath.Abs(s.configPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("[Lavender] Failed to get absolute config path")
|
log.Fatal("[Lavender] Failed to get absolute config path")
|
||||||
}
|
}
|
||||||
wd := filepath.Dir(configPathAbs)
|
wd := filepath.Dir(configPathAbs)
|
||||||
normalLoad(config, wd)
|
|
||||||
return subcommands.ExitSuccess
|
|
||||||
}
|
|
||||||
|
|
||||||
func normalLoad(startUp server.Conf, wd string) {
|
mSign, err := mjwt.NewMJwtSignerFromFileOrCreate(conf.Issuer, filepath.Join(wd, "lavender.private.key"), rand.Reader, 4096)
|
||||||
mSign, err := mjwt.NewMJwtSignerFromFileOrCreate(startUp.Issuer, filepath.Join(wd, "lavender.private.key"), rand.Reader, 4096)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("[Lavender] Failed to load or create MJWT signer:", err)
|
log.Fatal("[Lavender] Failed to load or create MJWT signer:", err)
|
||||||
}
|
}
|
||||||
@ -81,14 +71,35 @@ func normalLoad(startUp server.Conf, wd string) {
|
|||||||
log.Fatal("[Lavender] Failed to load page templates:", err)
|
log.Fatal("[Lavender] Failed to load page templates:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
srv := server.NewHttpServer(startUp, mSign)
|
srv := server.NewHttpServer(conf, mSign)
|
||||||
log.Printf("[Lavender] Starting HTTP server on '%s'\n", srv.Addr)
|
log.Printf("[Lavender] Starting HTTP server on '%s'\n", srv.Server.Addr)
|
||||||
go utils.RunBackgroundHttp("HTTP", srv)
|
go utils.RunBackgroundHttp("HTTP", srv.Server)
|
||||||
|
|
||||||
exit_reload.ExitReload("Tulip", func() {}, func() {
|
exit_reload.ExitReload("Lavender", func() {
|
||||||
|
var conf server.Conf
|
||||||
|
err := loadConfig(s.configPath, &conf)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("[Lavender] Failed to read config:", err)
|
||||||
|
}
|
||||||
|
err = srv.UpdateConfig(conf)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("[Lavender] Failed to reload config:", err)
|
||||||
|
}
|
||||||
|
}, func() {
|
||||||
// stop http server
|
// stop http server
|
||||||
_ = srv.Close()
|
_ = srv.Server.Close()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return subcommands.ExitSuccess
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadConfig(configPath string, conf *server.Conf) error {
|
||||||
|
openConf, err := os.Open(configPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.NewDecoder(openConf).Decode(conf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveMjwtPubKey(mSign mjwt.Signer, wd string) {
|
func saveMjwtPubKey(mSign mjwt.Signer, wd string) {
|
||||||
|
@ -12,7 +12,7 @@ type Conf struct {
|
|||||||
Issuer string `json:"issuer"`
|
Issuer string `json:"issuer"`
|
||||||
SsoServices []issuer.SsoConfig `json:"sso_services"`
|
SsoServices []issuer.SsoConfig `json:"sso_services"`
|
||||||
AllowedClients []AllowedClient `json:"allowed_clients"`
|
AllowedClients []AllowedClient `json:"allowed_clients"`
|
||||||
Ownership DomainOwnership `json:"ownership"`
|
Users UserConfig `json:"users"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AllowedClient struct {
|
type AllowedClient struct {
|
||||||
|
@ -37,14 +37,14 @@ func (h *HttpServer) flowPopup(rw http.ResponseWriter, req *http.Request, _ http
|
|||||||
cookie, err := req.Cookie("lavender-login-name")
|
cookie, err := req.Cookie("lavender-login-name")
|
||||||
if err == nil && cookie.Valid() == nil {
|
if err == nil && cookie.Valid() == nil {
|
||||||
pages.RenderPageTemplate(rw, "flow-popup-memory", map[string]any{
|
pages.RenderPageTemplate(rw, "flow-popup-memory", map[string]any{
|
||||||
"ServiceName": h.conf.ServiceName,
|
"ServiceName": h.conf.Load().ServiceName,
|
||||||
"Origin": req.URL.Query().Get("origin"),
|
"Origin": req.URL.Query().Get("origin"),
|
||||||
"LoginName": cookie.Value,
|
"LoginName": cookie.Value,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
pages.RenderPageTemplate(rw, "flow-popup", map[string]any{
|
pages.RenderPageTemplate(rw, "flow-popup", map[string]any{
|
||||||
"ServiceName": h.conf.ServiceName,
|
"ServiceName": h.conf.Load().ServiceName,
|
||||||
"Origin": req.URL.Query().Get("origin"),
|
"Origin": req.URL.Query().Get("origin"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -68,7 +68,7 @@ func (h *HttpServer) flowPopupPost(rw http.ResponseWriter, req *http.Request, _
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
loginName := req.PostFormValue("loginname")
|
loginName := req.PostFormValue("loginname")
|
||||||
login := h.manager.FindServiceFromLogin(loginName)
|
login := h.manager.Load().FindServiceFromLogin(loginName)
|
||||||
if login == nil {
|
if login == nil {
|
||||||
http.Error(rw, "No login service defined for this username", http.StatusBadRequest)
|
http.Error(rw, "No login service defined for this username", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
@ -90,7 +90,7 @@ func (h *HttpServer) flowPopupPost(rw http.ResponseWriter, req *http.Request, _
|
|||||||
})
|
})
|
||||||
|
|
||||||
targetOrigin := req.PostFormValue("origin")
|
targetOrigin := req.PostFormValue("origin")
|
||||||
allowedService, found := h.services[targetOrigin]
|
allowedService, found := (*h.services.Load())[targetOrigin]
|
||||||
if !found {
|
if !found {
|
||||||
http.Error(rw, "Invalid target origin", http.StatusBadRequest)
|
http.Error(rw, "Invalid target origin", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
@ -105,7 +105,7 @@ func (h *HttpServer) flowPopupPost(rw http.ResponseWriter, req *http.Request, _
|
|||||||
|
|
||||||
// generate oauth2 config and redirect to authorize URL
|
// generate oauth2 config and redirect to authorize URL
|
||||||
oa2conf := login.OAuth2Config
|
oa2conf := login.OAuth2Config
|
||||||
oa2conf.RedirectURL = h.conf.BaseUrl + "/callback"
|
oa2conf.RedirectURL = h.conf.Load().BaseUrl + "/callback"
|
||||||
nextUrl := oa2conf.AuthCodeURL(state, oauth2.SetAuthURLParam("login_name", loginUn))
|
nextUrl := oa2conf.AuthCodeURL(state, oauth2.SetAuthURLParam("login_name", loginUn))
|
||||||
http.Redirect(rw, req, nextUrl, http.StatusFound)
|
http.Redirect(rw, req, nextUrl, http.StatusFound)
|
||||||
}
|
}
|
||||||
@ -120,7 +120,7 @@ func (h *HttpServer) flowCallback(rw http.ResponseWriter, req *http.Request, _ h
|
|||||||
q := req.URL.Query()
|
q := req.URL.Query()
|
||||||
state := q.Get("state")
|
state := q.Get("state")
|
||||||
n := strings.IndexByte(state, ':')
|
n := strings.IndexByte(state, ':')
|
||||||
if n == -1 || !h.manager.CheckNamespace(state[:n]) {
|
if n == -1 || !h.manager.Load().CheckNamespace(state[:n]) {
|
||||||
http.Error(rw, "Invalid state namespace", http.StatusBadRequest)
|
http.Error(rw, "Invalid state namespace", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -131,7 +131,7 @@ func (h *HttpServer) flowCallback(rw http.ResponseWriter, req *http.Request, _ h
|
|||||||
}
|
}
|
||||||
|
|
||||||
oa2conf := v.sso.OAuth2Config
|
oa2conf := v.sso.OAuth2Config
|
||||||
oa2conf.RedirectURL = h.conf.BaseUrl + "/callback"
|
oa2conf.RedirectURL = h.conf.Load().BaseUrl + "/callback"
|
||||||
exchange, err := testOa2Exchange(oa2conf, context.Background(), q.Get("code"))
|
exchange, err := testOa2Exchange(oa2conf, context.Background(), q.Get("code"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("Failed exchange:", err)
|
fmt.Println("Failed exchange:", err)
|
||||||
@ -193,25 +193,22 @@ func (h *HttpServer) flowCallback(rw http.ResponseWriter, req *http.Request, _ h
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
n := strings.IndexByte(address.Address, '@')
|
n := strings.IndexByte(address.Address, '@')
|
||||||
if n == -1 {
|
if n != -1 {
|
||||||
goto noEmailSupport
|
if address.Address[n+1:] == v.sso.Config.Namespace {
|
||||||
|
ps.Set("mail:client")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if address.Address[n+1:] != v.sso.Config.Namespace {
|
|
||||||
goto noEmailSupport
|
|
||||||
}
|
|
||||||
ps.Set("mail-client")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if needsDomains {
|
if needsDomains {
|
||||||
a := h.conf.Ownership.AllOwns(sub + "@" + v.sso.Config.Namespace)
|
a := h.conf.Load().Users.AllDomains(sub + "@" + v.sso.Config.Namespace)
|
||||||
for _, i := range a {
|
for _, i := range a {
|
||||||
ps.Set("domain:owns=" + i)
|
ps.Set("domain:owns=" + i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
noEmailSupport:
|
|
||||||
nsSub := sub + "@" + v.sso.Config.Namespace
|
nsSub := sub + "@" + v.sso.Config.Namespace
|
||||||
ati := uuidNewStringAti()
|
ati := uuidNewStringAti()
|
||||||
accessToken, err := h.signer.GenerateJwt(nsSub, ati, jwt.ClaimStrings{aud}, 15*time.Minute, auth.AccessTokenClaims{
|
accessToken, err := h.signer.GenerateJwt(nsSub, ati, jwt.ClaimStrings{aud}, 15*time.Minute, auth.AccessTokenClaims{
|
||||||
@ -229,7 +226,7 @@ noEmailSupport:
|
|||||||
}
|
}
|
||||||
|
|
||||||
pages.RenderPageTemplate(rw, "flow-callback", map[string]any{
|
pages.RenderPageTemplate(rw, "flow-callback", map[string]any{
|
||||||
"ServiceName": h.conf.ServiceName,
|
"ServiceName": h.conf.Load().ServiceName,
|
||||||
"TargetOrigin": v.target.Url.String(),
|
"TargetOrigin": v.target.Url.String(),
|
||||||
"TargetMessage": v3,
|
"TargetMessage": v3,
|
||||||
"AccessToken": accessToken,
|
"AccessToken": accessToken,
|
||||||
|
@ -65,19 +65,20 @@ var testOidc = &issuer.WellKnownOIDC{
|
|||||||
|
|
||||||
var testManager = issuer.NewManagerForTests([]*issuer.WellKnownOIDC{testOidc})
|
var testManager = issuer.NewManagerForTests([]*issuer.WellKnownOIDC{testOidc})
|
||||||
var testHttpServer = HttpServer{
|
var testHttpServer = HttpServer{
|
||||||
r: nil,
|
r: nil,
|
||||||
conf: Conf{
|
|
||||||
BaseUrl: lavenderDomain,
|
|
||||||
ServiceName: "Test Lavender Service",
|
|
||||||
},
|
|
||||||
manager: testManager,
|
|
||||||
flowState: cache.New[string, flowStateData](),
|
flowState: cache.New[string, flowStateData](),
|
||||||
services: map[string]AllowedClient{
|
|
||||||
clientAppDomain: {},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
testHttpServer.conf.Store(&Conf{
|
||||||
|
BaseUrl: lavenderDomain,
|
||||||
|
ServiceName: "Test Lavender Service",
|
||||||
|
})
|
||||||
|
testHttpServer.manager.Store(testManager)
|
||||||
|
testHttpServer.services.Store(&map[string]AllowedClient{
|
||||||
|
clientAppDomain: {},
|
||||||
|
})
|
||||||
|
|
||||||
err := pages.LoadPages("")
|
err := pages.LoadPages("")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -103,7 +104,8 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFlowPopup(t *testing.T) {
|
func TestFlowPopup(t *testing.T) {
|
||||||
h := HttpServer{conf: Conf{ServiceName: "Test Service Name"}}
|
h := HttpServer{}
|
||||||
|
h.conf.Store(&Conf{ServiceName: "Test Service Name"})
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
req := httptest.NewRequest(http.MethodGet, "/popup?"+url.Values{"origin": []string{clientAppDomain}}.Encode(), nil)
|
req := httptest.NewRequest(http.MethodGet, "/popup?"+url.Values{"origin": []string{clientAppDomain}}.Encode(), nil)
|
||||||
h.flowPopup(rec, req, httprouter.Params{})
|
h.flowPopup(rec, req, httprouter.Params{})
|
||||||
|
@ -1,14 +1,30 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
// DomainOwnership is the structure for storing if a user owns a domain
|
// UserConfig is the structure for storing a user's role and owned domains
|
||||||
type DomainOwnership map[string][]string
|
type UserConfig map[string]struct {
|
||||||
|
Roles []string `json:"roles"`
|
||||||
func (d DomainOwnership) AllOwns(user string) []string {
|
Domains []string `json:"domains"`
|
||||||
return d[user]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d DomainOwnership) Owns(user, domain string) bool {
|
func (u UserConfig) AllRoles(user string) []string {
|
||||||
for _, i := range d[user] {
|
return u[user].Roles
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UserConfig) HasRole(user, role string) bool {
|
||||||
|
for _, i := range u[user].Roles {
|
||||||
|
if i == role {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UserConfig) AllDomains(user string) []string {
|
||||||
|
return u[user].Domains
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u UserConfig) OwnsDomain(user, domain string) bool {
|
||||||
|
for _, i := range u[user].Domains {
|
||||||
if i == domain {
|
if i == domain {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -8,16 +8,18 @@ import (
|
|||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HttpServer struct {
|
type HttpServer struct {
|
||||||
|
Server *http.Server
|
||||||
r *httprouter.Router
|
r *httprouter.Router
|
||||||
conf Conf
|
conf atomic.Pointer[Conf]
|
||||||
manager *issuer.Manager
|
manager atomic.Pointer[issuer.Manager]
|
||||||
signer mjwt.Signer
|
signer mjwt.Signer
|
||||||
flowState *cache.Cache[string, flowStateData]
|
flowState *cache.Cache[string, flowStateData]
|
||||||
services map[string]AllowedClient
|
services atomic.Pointer[map[string]AllowedClient]
|
||||||
}
|
}
|
||||||
|
|
||||||
type flowStateData struct {
|
type flowStateData struct {
|
||||||
@ -25,7 +27,7 @@ type flowStateData struct {
|
|||||||
target AllowedClient
|
target AllowedClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHttpServer(conf Conf, signer mjwt.Signer) *http.Server {
|
func NewHttpServer(conf Conf, signer mjwt.Signer) *HttpServer {
|
||||||
r := httprouter.New()
|
r := httprouter.New()
|
||||||
|
|
||||||
// remove last slash from baseUrl
|
// remove last slash from baseUrl
|
||||||
@ -36,23 +38,24 @@ func NewHttpServer(conf Conf, signer mjwt.Signer) *http.Server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
manager, err := issuer.NewManager(conf.SsoServices)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("[Lavender] Failed to create SSO service manager: ", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
services := make(map[string]AllowedClient)
|
|
||||||
for _, i := range conf.AllowedClients {
|
|
||||||
services[i.Url.String()] = i
|
|
||||||
}
|
|
||||||
|
|
||||||
hs := &HttpServer{
|
hs := &HttpServer{
|
||||||
|
Server: &http.Server{
|
||||||
|
Addr: conf.Listen,
|
||||||
|
Handler: r,
|
||||||
|
ReadTimeout: time.Minute,
|
||||||
|
ReadHeaderTimeout: time.Minute,
|
||||||
|
WriteTimeout: time.Minute,
|
||||||
|
IdleTimeout: time.Minute,
|
||||||
|
MaxHeaderBytes: 2500,
|
||||||
|
},
|
||||||
r: r,
|
r: r,
|
||||||
conf: conf,
|
|
||||||
manager: manager,
|
|
||||||
signer: signer,
|
signer: signer,
|
||||||
flowState: cache.New[string, flowStateData](),
|
flowState: cache.New[string, flowStateData](),
|
||||||
services: services,
|
}
|
||||||
|
err := hs.UpdateConfig(conf)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Failed to load initial config:", err)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
r.GET("/", func(rw http.ResponseWriter, req *http.Request, _ httprouter.Params) {
|
r.GET("/", func(rw http.ResponseWriter, req *http.Request, _ httprouter.Params) {
|
||||||
@ -63,14 +66,22 @@ func NewHttpServer(conf Conf, signer mjwt.Signer) *http.Server {
|
|||||||
r.GET("/popup", hs.flowPopup)
|
r.GET("/popup", hs.flowPopup)
|
||||||
r.POST("/popup", hs.flowPopupPost)
|
r.POST("/popup", hs.flowPopupPost)
|
||||||
r.GET("/callback", hs.flowCallback)
|
r.GET("/callback", hs.flowCallback)
|
||||||
|
return hs
|
||||||
return &http.Server{
|
}
|
||||||
Addr: conf.Listen,
|
|
||||||
Handler: r,
|
func (h *HttpServer) UpdateConfig(conf Conf) error {
|
||||||
ReadTimeout: time.Minute,
|
m, err := issuer.NewManager(conf.SsoServices)
|
||||||
ReadHeaderTimeout: time.Minute,
|
if err != nil {
|
||||||
WriteTimeout: time.Minute,
|
return fmt.Errorf("failed to reload SSO service manager: %w", err)
|
||||||
IdleTimeout: time.Minute,
|
}
|
||||||
MaxHeaderBytes: 2500,
|
|
||||||
}
|
clientLookup := make(map[string]AllowedClient)
|
||||||
|
for _, i := range conf.AllowedClients {
|
||||||
|
clientLookup[i.Url.String()] = i
|
||||||
|
}
|
||||||
|
|
||||||
|
h.conf.Store(&conf)
|
||||||
|
h.manager.Store(m)
|
||||||
|
h.services.Store(&clientLookup)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/1f349/violet/utils"
|
|
||||||
"github.com/1f349/mjwt"
|
"github.com/1f349/mjwt"
|
||||||
"github.com/1f349/mjwt/auth"
|
"github.com/1f349/mjwt/auth"
|
||||||
|
"github.com/1f349/violet/utils"
|
||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
@ -24,7 +24,7 @@ func (h *HttpServer) verifyHandler(rw http.ResponseWriter, req *http.Request, _
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check issuer against config
|
// check issuer against config
|
||||||
if b.Issuer != h.conf.Issuer {
|
if b.Issuer != h.conf.Load().Issuer {
|
||||||
http.Error(rw, "Invalid issuer", http.StatusBadRequest)
|
http.Error(rw, "Invalid issuer", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -20,9 +20,9 @@ func TestVerifyHandler(t *testing.T) {
|
|||||||
|
|
||||||
invalidSigner := mjwt.NewMJwtSigner("Invalid Issuer", privKey)
|
invalidSigner := mjwt.NewMJwtSigner("Invalid Issuer", privKey)
|
||||||
h := HttpServer{
|
h := HttpServer{
|
||||||
conf: Conf{Issuer: "Test Issuer"},
|
|
||||||
signer: mjwt.NewMJwtSigner("Test Issuer", privKey),
|
signer: mjwt.NewMJwtSigner("Test Issuer", privKey),
|
||||||
}
|
}
|
||||||
|
h.conf.Store(&Conf{Issuer: "Test Issuer"})
|
||||||
|
|
||||||
// test for missing bearer response
|
// test for missing bearer response
|
||||||
rec := httptest.NewRecorder()
|
rec := httptest.NewRecorder()
|
||||||
|
Loading…
Reference in New Issue
Block a user