Load Attributes service extension (Legacy)

Load Attributes service extension (Legacy)

ℹ️
This topic refers to legacy configuration syntax. App gateways are now defined as Proxy apps.

Service Extensions allow complete flexibility over the process of controlling access into protected resources.

How AppGateways Serve Traffic

A little context will be helpful to understand how loading attributes works and where it fits into the identity flow of a user. Here is how traffic flows into an AppGateway (in pseudocode).

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

This is a simplification. The actual implementation caches the information about the session for efficiency, including the results of the authentication and authorization check. As such, each of these methods is not usually called for each request, but rather only for the first pass through for the user.

Loading Attributes

As seen above in pseudocode, loading attributes will occur after the user’s identity has been established.

LoadAttributes Service Extension

This Service Extension is used to load information about the authenticated user. Typically the attribute information will be stored on the session, allowing it to be used for making policy decisions or for it to be used in headers passed to the protected resource.

⚠️
Although this Service Extension is being passed the http.ResponseWriter, typically it will not send any response directly to the user. Writing to the http.ResponseWriter’s body or headers may produce undesired behavior.
appgateways:
  - name: alpha
    # ...

    attrProviders:
      - connector: ldap

    loadAttrsSE:
      funcName: LoadAttrs
      file: /etc/maverics/extensions/loadAttrs.go

    policies:
      - location: /
        authentication:
          idps:
            - azure
        authorization:
          allowAll: true

/etc/maverics/extensions/loadAttrs.go

package main

import (
	"fmt"
	"net/http"

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

// LoadAttrs loads attributes from LDAP and then stores them on the session for later
// use.
func LoadAttrs(ag *app.AppGateway, rw http.ResponseWriter, req *http.Request) error {
	log.Debug("msg", "loading attributes from LDAP")

	mail := session.GetString(req, "azure.email")
	if mail == "" {
		return fmt.Errorf("failed to find user email required for LDAP query")
	}

	ldap, ok := ag.AttrProviders["ldap"]
	if !ok {
		return fmt.Errorf("failed to find LDAP attribute provider")
	}

	targetAttrs := []string{"cn", "sn", "mobile"}
	attrs, err := ldap.Query(mail, targetAttrs)
	if err != nil {
		return fmt.Errorf("failed to query LDAP: %w", err)
	}

	for k, v := range attrs {
		log.Debug(
			"msg", "setting LDAP attribute on session",
			"attribute", k,
			"value", v,
		)
		session.Set(req, k, v)
	}

	return nil
}