func checkAuthorization()

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
}