mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
* AuthN: Add basic auth client boilerplate * AuthN: Implement test function for basic auth client * AuthN: Implement the authentication method for basic auth * AuthN: Add tests for basic auth authentication * ContextHandler: perform basic auth authentication through authn service if feature toggle is enabled * AuthN: Add providers for sync services and pass required dependencies
167 lines
4.0 KiB
Go
167 lines
4.0 KiB
Go
package authn
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/grafana/grafana/pkg/models"
|
|
"github.com/grafana/grafana/pkg/services/org"
|
|
"github.com/grafana/grafana/pkg/services/user"
|
|
"golang.org/x/oauth2"
|
|
)
|
|
|
|
const (
|
|
ClientAPIKey = "auth.client.api-key" // #nosec G101
|
|
ClientAnonymous = "auth.client.anonymous"
|
|
ClientBasic = "auth.client.basic"
|
|
)
|
|
|
|
type ClientParams struct {
|
|
SyncUser bool
|
|
AllowSignUp bool
|
|
EnableDisabledUsers bool
|
|
}
|
|
|
|
type PostAuthHookFn func(ctx context.Context, clientParams *ClientParams, identity *Identity) error
|
|
|
|
type Service interface {
|
|
// RegisterPostAuthHook registers a hook that is called after a successful authentication.
|
|
RegisterPostAuthHook(hook PostAuthHookFn)
|
|
// Authenticate authenticates a request using the specified client.
|
|
Authenticate(ctx context.Context, client string, r *Request) (*Identity, bool, error)
|
|
}
|
|
|
|
type Client interface {
|
|
// Authenticate performs the authentication for the request
|
|
Authenticate(ctx context.Context, r *Request) (*Identity, error)
|
|
ClientParams() *ClientParams
|
|
// Test should return true if client can be used to authenticate request
|
|
Test(ctx context.Context, r *Request) bool
|
|
}
|
|
|
|
type Request struct {
|
|
// OrgID will be populated by authn.Service
|
|
OrgID int64
|
|
HTTPRequest *http.Request
|
|
}
|
|
|
|
const (
|
|
NamespaceUser = "user"
|
|
NamespaceAPIKey = "api-key"
|
|
NamespaceServiceAccount = "service-account"
|
|
)
|
|
|
|
type Identity struct {
|
|
OrgID int64
|
|
OrgCount int
|
|
OrgName string
|
|
OrgRoles map[int64]org.RoleType
|
|
|
|
ID string
|
|
Login string
|
|
Name string
|
|
Email string
|
|
IsGrafanaAdmin *bool
|
|
AuthModule string // AuthModule is the name of the external system
|
|
AuthID string // AuthId is the unique identifier for the user in the external system
|
|
OAuthToken *oauth2.Token
|
|
LookUpParams models.UserLookupParams
|
|
IsDisabled bool
|
|
HelpFlags1 user.HelpFlags1
|
|
LastSeenAt time.Time
|
|
Teams []int64
|
|
}
|
|
|
|
func (i *Identity) Role() org.RoleType {
|
|
return i.OrgRoles[i.OrgID]
|
|
}
|
|
|
|
// IsAnonymous will return true if no ID is set on the identity
|
|
func (i *Identity) IsAnonymous() bool {
|
|
return i.ID == ""
|
|
}
|
|
|
|
// TODO: improve error handling
|
|
func (i *Identity) NamespacedID() (string, int64) {
|
|
var (
|
|
id int64
|
|
namespace string
|
|
)
|
|
|
|
split := strings.Split(i.ID, ":")
|
|
if len(split) != 2 {
|
|
return "", -1
|
|
}
|
|
|
|
id, errI := strconv.ParseInt(split[1], 10, 64)
|
|
if errI != nil {
|
|
return "", -1
|
|
}
|
|
|
|
namespace = split[0]
|
|
|
|
return namespace, id
|
|
}
|
|
|
|
func (i *Identity) SignedInUser() *user.SignedInUser {
|
|
var isGrafanaAdmin bool
|
|
if i.IsGrafanaAdmin != nil {
|
|
isGrafanaAdmin = *i.IsGrafanaAdmin
|
|
}
|
|
|
|
u := &user.SignedInUser{
|
|
UserID: 0,
|
|
OrgID: i.OrgID,
|
|
OrgName: i.OrgName,
|
|
OrgRole: i.Role(),
|
|
ExternalAuthModule: i.AuthModule,
|
|
ExternalAuthID: i.AuthID,
|
|
Login: i.Login,
|
|
Name: i.Name,
|
|
Email: i.Email,
|
|
OrgCount: i.OrgCount,
|
|
IsGrafanaAdmin: isGrafanaAdmin,
|
|
IsAnonymous: i.IsAnonymous(),
|
|
IsDisabled: i.IsDisabled,
|
|
HelpFlags1: i.HelpFlags1,
|
|
LastSeenAt: i.LastSeenAt,
|
|
Teams: i.Teams,
|
|
}
|
|
|
|
namespace, id := i.NamespacedID()
|
|
if namespace == NamespaceAPIKey {
|
|
u.ApiKeyID = id
|
|
} else {
|
|
u.UserID = id
|
|
u.IsServiceAccount = namespace == NamespaceServiceAccount
|
|
}
|
|
|
|
return u
|
|
}
|
|
|
|
func NamespacedID(namespace string, id int64) string {
|
|
return fmt.Sprintf("%s:%d", namespace, id)
|
|
}
|
|
|
|
func IdentityFromSignedInUser(id string, usr *user.SignedInUser) *Identity {
|
|
return &Identity{
|
|
ID: id,
|
|
OrgID: usr.OrgID,
|
|
OrgName: usr.OrgName,
|
|
OrgRoles: map[int64]org.RoleType{usr.OrgID: usr.OrgRole},
|
|
Login: usr.Login,
|
|
Name: usr.Name,
|
|
Email: usr.Email,
|
|
OrgCount: usr.OrgCount,
|
|
IsGrafanaAdmin: &usr.IsGrafanaAdmin,
|
|
IsDisabled: usr.IsDisabled,
|
|
HelpFlags1: usr.HelpFlags1,
|
|
LastSeenAt: usr.LastSeenAt,
|
|
Teams: usr.Teams,
|
|
}
|
|
}
|