in lib/dam/dam.go [599:668]
func checkAuthorization(ctx context.Context, id *ga4gh.Identity, ttl time.Duration, resourceName, viewName, roleName string, cfg *pb.DamConfig, client string, vopts ValidateCfgOpts) error {
if stat := checkTrustedIssuer(id.Issuer, cfg, vopts); stat != nil {
return errutil.WithErrorReason(errUntrustedIssuer, stat.Err())
}
srcRes, ok := cfg.Resources[resourceName]
if !ok {
return errutil.WithErrorReason(errResourceNotFound, status.Errorf(codes.NotFound, "resource %q not found", resourceName))
}
srcView, ok := srcRes.Views[viewName]
if !ok {
return errutil.WithErrorReason(errResourceViewNotFound, status.Errorf(codes.NotFound, "resource %q view %q not found", resourceName, viewName))
}
entries, err := resolveAggregates(srcRes, srcView, cfg, vopts.Services)
if err != nil {
return errutil.WithErrorReason(errResolveAggregatesFail, status.Error(codes.PermissionDenied, err.Error()))
}
active := false
for _, entry := range entries {
// Step 1: validation.
view := entry.View
res := entry.Res
vRole, ok := view.Roles[roleName]
if !ok {
return errutil.WithErrorReason(errRoleNotAvailable, status.Errorf(codes.PermissionDenied, "unauthorized for resource %q view %q role %q (role not available on this view)", resourceName, viewName, roleName))
}
_, err := adapter.ResolveServiceRole(roleName, view, res, cfg)
if err != nil {
return errutil.WithErrorReason(errCannotResolveServiceRole, status.Errorf(codes.PermissionDenied, "unauthorized for resource %q view %q role %q (cannot resolve service role)", resourceName, viewName, roleName))
}
// Step 3: check visa policies.
if len(vRole.Policies) == 0 {
return errutil.WithErrorReason(errNoPolicyDefined, status.Errorf(codes.PermissionDenied, "unauthorized for resource %q view %q role %q (no policy defined for this view's role)", resourceName, viewName, roleName))
}
ctxWithTTL := context.WithValue(ctx, validator.RequestTTLInNanoFloat64, float64(ttl.Nanoseconds())/1e9)
for _, p := range vRole.Policies {
if p.Name == allowlistPolicyName {
ok, err := checkAllowlist(p.Args, id, cfg, vopts)
if err != nil {
return errutil.WithErrorReason(errAllowlistUnavailable, status.Errorf(codes.PermissionDenied, "unauthorized for resource %q view %q role %q (allowlist unavailable): %v", resourceName, viewName, roleName, err))
}
if !ok {
return errutil.WithErrorReason(errRejectedPolicy, status.Errorf(codes.PermissionDenied, "unauthorized for resource %q view %q role %q (user not on allowlist)", resourceName, viewName, roleName))
}
active = true
continue
}
v, err := buildValidator(ctxWithTTL, p, vRole, cfg)
if err != nil {
return errutil.WithErrorReason(errCannotEnforcePolicies, status.Errorf(codes.PermissionDenied, "cannot enforce policies for resource %q view %q role %q: %v", resourceName, viewName, roleName, err))
}
ok, err = v.Validate(ctxWithTTL, id)
if err != nil {
// Strip internal error in case it contains any sensitive data.
return errutil.WithErrorReason(errCannotValidateIdentity, status.Errorf(codes.PermissionDenied, "cannot validate identity (subject %q, issuer %q): internal error", id.Subject, id.Issuer))
}
if !ok {
details := buildRejectedPolicy(resourceName+"/"+viewName+"/"+roleName, id.RejectedVisas, makePolicyBasis(roleName, view, res, cfg, vopts.HidePolicyBasis, vopts.Services), vopts)
return errutil.WithErrorReason(errRejectedPolicy, withRejectedPolicy(details, status.Errorf(codes.PermissionDenied, "unauthorized for resource %q view %q role %q (policy requirements failed)", resourceName, viewName, roleName)))
}
active = true
}
}
if !active {
return errutil.WithErrorReason(errRoleNotEnabled, status.Errorf(codes.PermissionDenied, "unauthorized for resource %q view %q role %q (role not enabled)", resourceName, viewName, roleName))
}
return nil
}