Authorization service extension (Legacy)
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 the authorization 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 *app.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.
Authorization
As seen above in pseudocode, authorization will occur after the user’s identity has been established via authentication and user attributes are loaded. Authorization is then applied to control access to the requested resource.
AuthN vs. AuthZ
Authentication (AuthN) is used simply to assert the user’s identity, not to determine if they have access. A user may be authenticated, but may still be denied access at the Authorization (AuthZ) stage.
IsAuthorized Service Extension
This Service Extension returns a boolean value indicating if access is allowed or denied. Typically, it will apply its logic based on attributes already available on the user’s session (e.g. loaded in the LoadAttrsSE
phase), or on intrinsic properties of the request.
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.Here is an example of the isAuthorizedSE
Service Extension implemented at both the
AppGateway and location level.
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"
}