mirror of
https://github.com/TwiN/gatus.git
synced 2024-12-02 21:04:25 +01:00
123 lines
5.2 KiB
Go
123 lines
5.2 KiB
Go
package g8
|
|
|
|
import (
|
|
"sync"
|
|
)
|
|
|
|
// AuthorizationService is the service that manages client/token registry and client fallback as well as the service
|
|
// that determines whether a token meets the specific requirements to be authorized by a Gate or not.
|
|
type AuthorizationService struct {
|
|
clients map[string]*Client
|
|
clientProvider *ClientProvider
|
|
|
|
mutex sync.RWMutex
|
|
}
|
|
|
|
// NewAuthorizationService creates a new AuthorizationService
|
|
func NewAuthorizationService() *AuthorizationService {
|
|
return &AuthorizationService{
|
|
clients: make(map[string]*Client),
|
|
}
|
|
}
|
|
|
|
// WithToken is used to specify a single token for which authorization will be granted
|
|
//
|
|
// The client that will be created from this token will have access to all handlers that are not protected with a
|
|
// specific permission.
|
|
//
|
|
// In other words, if you were to do the following:
|
|
// gate := g8.New().WithAuthorizationService(g8.NewAuthorizationService().WithToken("12345"))
|
|
//
|
|
// The following handler would be accessible with the token 12345:
|
|
// router.Handle("/1st-handler", gate.Protect(yourHandler))
|
|
//
|
|
// But not this one would not be accessible with the token 12345:
|
|
// router.Handle("/2nd-handler", gate.ProtectWithPermissions(yourOtherHandler, []string{"admin"}))
|
|
//
|
|
// Calling this function multiple times will add multiple clients, though you may want to use WithTokens instead
|
|
// if you plan to add multiple clients
|
|
//
|
|
// If you wish to configure advanced permissions, consider using WithClient instead.
|
|
//
|
|
func (authorizationService *AuthorizationService) WithToken(token string) *AuthorizationService {
|
|
authorizationService.mutex.Lock()
|
|
authorizationService.clients[token] = NewClient(token)
|
|
authorizationService.mutex.Unlock()
|
|
return authorizationService
|
|
}
|
|
|
|
// WithTokens is used to specify a slice of tokens for which authorization will be granted
|
|
func (authorizationService *AuthorizationService) WithTokens(tokens []string) *AuthorizationService {
|
|
authorizationService.mutex.Lock()
|
|
for _, token := range tokens {
|
|
authorizationService.clients[token] = NewClient(token)
|
|
}
|
|
authorizationService.mutex.Unlock()
|
|
return authorizationService
|
|
}
|
|
|
|
// WithClient is used to specify a single client for which authorization will be granted
|
|
//
|
|
// When compared to WithToken, the advantage of using this function is that you may specify the client's
|
|
// permissions and thus, be a lot more granular with what endpoint a token has access to.
|
|
//
|
|
// In other words, if you were to do the following:
|
|
// gate := g8.New().WithAuthorizationService(g8.NewAuthorizationService().WithClient(g8.NewClient("12345").WithPermission("mod")))
|
|
//
|
|
// The following handlers would be accessible with the token 12345:
|
|
// router.Handle("/1st-handler", gate.ProtectWithPermissions(yourHandler, []string{"mod"}))
|
|
// router.Handle("/2nd-handler", gate.Protect(yourOtherHandler))
|
|
//
|
|
// But not this one, because the user does not have the permission "admin":
|
|
// router.Handle("/3rd-handler", gate.ProtectWithPermissions(yetAnotherHandler, []string{"admin"}))
|
|
//
|
|
// Calling this function multiple times will add multiple clients, though you may want to use WithClients instead
|
|
// if you plan to add multiple clients
|
|
func (authorizationService *AuthorizationService) WithClient(client *Client) *AuthorizationService {
|
|
authorizationService.mutex.Lock()
|
|
authorizationService.clients[client.Token] = client
|
|
authorizationService.mutex.Unlock()
|
|
return authorizationService
|
|
}
|
|
|
|
// WithClients is used to specify a slice of clients for which authorization will be granted
|
|
func (authorizationService *AuthorizationService) WithClients(clients []*Client) *AuthorizationService {
|
|
authorizationService.mutex.Lock()
|
|
for _, client := range clients {
|
|
authorizationService.clients[client.Token] = client
|
|
}
|
|
authorizationService.mutex.Unlock()
|
|
return authorizationService
|
|
}
|
|
|
|
// WithClientProvider allows specifying a custom provider to fetch clients by token.
|
|
//
|
|
// For example, you can use it to fallback to making a call in your database when a request is made with a token that
|
|
// hasn't been specified via WithToken, WithTokens, WithClient or WithClients.
|
|
func (authorizationService *AuthorizationService) WithClientProvider(provider *ClientProvider) *AuthorizationService {
|
|
authorizationService.clientProvider = provider
|
|
return authorizationService
|
|
}
|
|
|
|
// IsAuthorized checks whether a client with a given token exists and has the permissions required.
|
|
//
|
|
// If permissionsRequired is nil or empty and a client with the given token exists, said client will have access to all
|
|
// handlers that are not protected by a given permission.
|
|
func (authorizationService *AuthorizationService) IsAuthorized(token string, permissionsRequired []string) bool {
|
|
if len(token) == 0 {
|
|
return false
|
|
}
|
|
authorizationService.mutex.RLock()
|
|
client, _ := authorizationService.clients[token]
|
|
authorizationService.mutex.RUnlock()
|
|
// If there's no clients with the given token directly stored in the AuthorizationService, fall back to the
|
|
// client provider, if there's one configured.
|
|
if client == nil && authorizationService.clientProvider != nil {
|
|
client = authorizationService.clientProvider.GetClientByToken(token)
|
|
}
|
|
if client != nil {
|
|
return client.HasPermissions(permissionsRequired)
|
|
}
|
|
return false
|
|
}
|