mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
AuthN: Perform login with authn.Service (#61466)
* AuthN: Create password client wrapper and use that on in basic auth client * AuthN: fix basic auth client test * AuthN: Add tests for form authentication * API: Inject authn service * Login: If authnService feature flag is enabled use authn login * Login: Handle token creation errors
This commit is contained in:
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/middleware/csrf"
|
||||
"github.com/grafana/grafana/pkg/services/auth"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/oauthtoken"
|
||||
"github.com/grafana/grafana/pkg/services/querylibrary"
|
||||
@@ -211,6 +212,7 @@ type HTTPServer struct {
|
||||
tagService tag.Service
|
||||
oauthTokenService oauthtoken.OAuthTokenService
|
||||
statsService stats.Service
|
||||
authnService authn.Service
|
||||
}
|
||||
|
||||
type ServerOptions struct {
|
||||
@@ -253,7 +255,7 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi
|
||||
accesscontrolService accesscontrol.Service, dashboardThumbsService thumbs.DashboardThumbService, navTreeService navtree.Service,
|
||||
annotationRepo annotations.Repository, tagService tag.Service, searchv2HTTPService searchV2.SearchHTTPService,
|
||||
queryLibraryHTTPService querylibrary.HTTPService, queryLibraryService querylibrary.Service, oauthTokenService oauthtoken.OAuthTokenService,
|
||||
statsService stats.Service,
|
||||
statsService stats.Service, authnService authn.Service,
|
||||
k8saccess k8saccess.K8SAccess, // required so that the router is registered
|
||||
) (*HTTPServer, error) {
|
||||
web.Env = cfg.Env
|
||||
@@ -360,6 +362,7 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi
|
||||
QueryLibraryService: queryLibraryService,
|
||||
oauthTokenService: oauthTokenService,
|
||||
statsService: statsService,
|
||||
authnService: authnService,
|
||||
}
|
||||
if hs.Listener != nil {
|
||||
hs.log.Debug("Using provided listener")
|
||||
|
||||
@@ -17,6 +17,8 @@ import (
|
||||
"github.com/grafana/grafana/pkg/middleware/cookies"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/auth"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
loginService "github.com/grafana/grafana/pkg/services/login"
|
||||
"github.com/grafana/grafana/pkg/services/secrets"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
@@ -167,6 +169,34 @@ func (hs *HTTPServer) LoginAPIPing(c *models.ReqContext) response.Response {
|
||||
}
|
||||
|
||||
func (hs *HTTPServer) LoginPost(c *models.ReqContext) response.Response {
|
||||
if hs.Features.IsEnabled(featuremgmt.FlagAuthnService) {
|
||||
identity, err := hs.authnService.Login(c.Req.Context(), authn.ClientForm, &authn.Request{HTTPRequest: c.Req, Resp: c.Resp})
|
||||
if err != nil {
|
||||
tokenErr := &auth.CreateTokenErr{}
|
||||
if errors.As(err, &tokenErr) {
|
||||
return response.Error(tokenErr.StatusCode, tokenErr.ExternalErr, tokenErr.InternalErr)
|
||||
}
|
||||
return response.Err(err)
|
||||
}
|
||||
|
||||
cookies.WriteSessionCookie(c, hs.Cfg, identity.SessionToken.UnhashedToken, hs.Cfg.LoginMaxLifetime)
|
||||
result := map[string]interface{}{
|
||||
"message": "Logged in",
|
||||
}
|
||||
|
||||
if redirectTo := c.GetCookie("redirect_to"); len(redirectTo) > 0 {
|
||||
if err := hs.ValidateRedirectTo(redirectTo); err == nil {
|
||||
result["redirectUrl"] = redirectTo
|
||||
} else {
|
||||
c.Logger.Info("Ignored invalid redirect_to cookie value.", "url", redirectTo)
|
||||
}
|
||||
cookies.DeleteCookie(c.Resp, "redirect_to", hs.CookieOptionsFromCfg)
|
||||
}
|
||||
|
||||
metrics.MApiLoginPost.Inc()
|
||||
return response.JSON(http.StatusOK, result)
|
||||
}
|
||||
|
||||
cmd := dtos.LoginCommand{}
|
||||
if err := web.Bind(c.Req, &cmd); err != nil {
|
||||
return response.Error(http.StatusBadRequest, "bad login data", err)
|
||||
|
||||
@@ -12,9 +12,6 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/api/dtos"
|
||||
"github.com/grafana/grafana/pkg/api/response"
|
||||
"github.com/grafana/grafana/pkg/api/routing"
|
||||
@@ -24,6 +21,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/login/social"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/auth/authtest"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/hooks"
|
||||
"github.com/grafana/grafana/pkg/services/licensing"
|
||||
loginservice "github.com/grafana/grafana/pkg/services/login"
|
||||
@@ -33,6 +31,8 @@ import (
|
||||
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func fakeSetIndexViewData(t *testing.T) {
|
||||
@@ -324,6 +324,7 @@ func TestLoginPostRedirect(t *testing.T) {
|
||||
HooksService: &hooks.HooksService{},
|
||||
License: &licensing.OSSLicensingService{},
|
||||
AuthTokenService: authtest.NewFakeUserAuthTokenService(),
|
||||
Features: featuremgmt.WithFeatures(),
|
||||
}
|
||||
hs.Cfg.CookieSecure = true
|
||||
|
||||
@@ -603,6 +604,7 @@ func TestLoginPostRunLokingHook(t *testing.T) {
|
||||
Cfg: setting.NewCfg(),
|
||||
License: &licensing.OSSLicensingService{},
|
||||
AuthTokenService: authtest.NewFakeUserAuthTokenService(),
|
||||
Features: featuremgmt.WithFeatures(),
|
||||
HooksService: hookService,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user