Extension de services d’autorisation (existante)

Extension de services d’autorisation (existante)

ℹ️
Cette rubrique fait référence à la syntaxe de configuration existante. Les passerelles d’applications sont désormais définies comme des applications Proxy. Un nouvel exemple de l’extension de services Authorization est présenté ici

Les extensions de services permettent une flexibilité totale dans le processus de contrôle d’accès aux ressources protégées.

Comment les passerelles d’applications gèrent le trafic

Un peu de contexte est nécessaire à la compréhension du fonctionnement du processus d’autorisation et de sa place dans le flux d’identité d’un utilisateur. Voici comment le trafic circule dans une AppGateway (en pseudocode).

func Serve(appGateway *app.AppGateway, rw http.ResponseWriter, req *http.Request) {
  if !isAuthenticated(){
    Authenticate(resp, req)
  }
  LoadAttrs()
  if IsAuthorized() {
    SetHeaders()
    Proxy()
  }
}

Il s’agit d’une simplification. La mise en œuvre effective met en cache les informations relatives à la session par souci d’efficacité, y compris les résultats de la vérification de l’authentification et de l’autorisation. Ainsi, ces méthodes ne sont généralement pas sollicitées pour chaque requête, mais uniquement lors du premier passage de l’utilisateur.

Autorisation

Comme le montre le pseudocode ci-dessus, l’autorisation intervient une fois que l’identité de l’utilisateur a été établie par le biais de l’authentification et que les attributs de l’utilisateur ont été chargés. Le processus d’autorisation est ensuite appliqué pour contrôler l’accès à la ressource demandée.

ℹ️

AuthN ou AuthZ

L’authentification (AuthN) sert simplement à confirmer l’identité de l’utilisateur, et non à déterminer s’il dispose d’un accès. Un utilisateur peut être authentifié, mais se voir refuser l’accès au stade de l’autorisation (AuthZ).

Extension de services IsAuthorized

Cette extension de services renvoie une valeur booléenne indiquant si l’accès est autorisé ou refusé. En règle générale, elle applique sa logique sur la base des attributs déjà disponibles dans la session de l’utilisateur (par exemple, ceux chargés lors de la phase LoadAttrsSE), ou sur la base des propriétés intrinsèques de la requête.

⚠️
Bien que cette extension de services reçoive le http.ResponseWriter, elle n’envoie généralement pas de réponse directement à l’utilisateur. L’écriture dans le corps ou les en-têtes de http.ResponseWriter peut entraîner un comportement indésirable.

Voici un exemple de l’extension de services isAuthorizedSE mise en œuvre à la fois au niveau de l’AppGateway et de l’emplacement.

appgateways:
  - name: alpha
    # ...

    isAuthorizedSE:
      funcName: DefaultIsAuthorized
      file: /etc/maverics/extensions/alpha/auth.go

    policies:
      - location: /
        authentication:
          idps:
            - azure

      - location: /admin
        authentication:
          idps:
            - azure
        authorization:
          isAuthorizedSE:
            funcName: AdminIsAuthorized
            file: /etc/maverics/extensions/alpha/auth.go

/etc/maverics/extensions/alpha/auth.go

package main

import (
	"net/http"
	"strings"

	"maverics/app"
	"maverics/log"
	"maverics/session"
)

// DefaultIsAuthorized ensures the user is a Canary Bank staffer.
func DefaultIsAuthorized(ag *app.AppGateway, rw http.ResponseWriter, req *http.Request) bool {
	log.Debug(
		"msg", "determining if user is authorized",
		"extension", "DefaultIsAuthorized",
	)

	if isCanaryStaffer(req) {
		return true
	}

	return false
}

// AdminIsAuthorized ensures the user is a Canary Bank staffer and that they
// work in the accounting department.
func AdminIsAuthorized(ag *app.AppGateway, rw http.ResponseWriter, req *http.Request) bool {
	log.Debug(
		"msg", "determining if user is authorized",
		"extension", "AdminIsAuthorized",
	)

	if isCanaryStaffer(req) && isAdmin(req) {
		return true
	}

	return false
}

func isCanaryStaffer(req *http.Request) bool {
	email := session.GetString(req, "azure.email")
	return strings.HasSuffix(email, "@canarybank.io")
}

func isAdmin(req *http.Request) bool {
	department := session.GetString(req, "ldap.department")
	return department == "Accounting"
}