func checkBasicIntegrity()

in lib/dam/dam_integrity.go [108:258]


func checkBasicIntegrity(cfg *pb.DamConfig, vopts ValidateCfgOpts) *status.Status {
	for n, ti := range cfg.TrustedIssuers {
		if err := checkName(n); err != nil {
			return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgTrustedPassportIssuer, n), err.Error())
		}
		if !httputils.IsHTTPS(ti.Issuer) && !httputils.IsLocalhost(ti.Issuer) {
			return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgTrustedPassportIssuer, n, "issuer"), "trusted identity must have an issuer of type HTTPS")
		}
		if _, ok := translators[ti.TranslateUsing]; !ok && len(ti.TranslateUsing) > 0 {
			return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgTrustedPassportIssuer, n, "translateUsing"), fmt.Sprintf("trusted identity with unknown translator %q", ti.TranslateUsing))
		}
		if path, err := check.CheckUI(ti.Ui, true); err != nil {
			return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgTrustedPassportIssuer, n, path), fmt.Sprintf("trusted passport issuer UI settings: %v", err))
		}
		if stat := checkTrustedIssuerClientCredentials(n, vopts.DefaultBroker, ti, vopts); stat != nil {
			return stat
		}
	}

	for n, ts := range cfg.TrustedSources {
		if err := checkName(n); err != nil {
			return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgTrustedSources, n), err.Error())
		}
		for i, source := range ts.Sources {
			if !httputils.IsHTTPS(source) {
				return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgTrustedSources, n, "sources", strconv.Itoa(i)), "trusted source URL must be HTTPS")
			}
		}
		for i, visa := range ts.VisaTypes {
			if _, ok := cfg.VisaTypes[visa]; !ok {
				return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgTrustedSources, n, "visaTypes", strconv.Itoa(i)), fmt.Sprintf("visa name %q not found in visa type definitions", visa))
			}
		}
		if path, err := check.CheckUI(ts.Ui, true); err != nil {
			return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgTrustedSources, n, path), fmt.Sprintf("trusted sources UI settings: %v", err))
		}
	}

	for n, policy := range cfg.Policies {
		if err := checkName(n); err != nil {
			return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgPolicies, n), err.Error())
		}
		if path, err := validator.ValidatePolicy(policy, cfg.VisaTypes, cfg.TrustedSources, nil); err != nil {
			return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgPolicies, n, path), err.Error())
		}
		if path, err := check.CheckUI(policy.Ui, true); err != nil {
			return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgPolicies, n, path), fmt.Sprintf("policies UI settings: %v", err))
		}
		// Note: there is no requirement that built-in policies be present. But if they are, they must not be edited.
		// Regular, non-built-in policies must not use reserved UI labels for built-in policies.
		builtin, ok := BuiltinPolicies[n]
		if ok && !proto.Equal(builtin, policy) {
			return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgPolicies, n), fmt.Sprintf("built-in policy cannot be edited"))
		}
		if !ok && policy.Ui["source"] != "" {
			return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgPolicies, n, "ui", "source"), fmt.Sprintf("%q label is reserved for built-in policies", "source"))
		}
		if !ok && policy.Ui["edit"] != "" {
			return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgPolicies, n, "ui", "edit"), fmt.Sprintf("%q label is reserved for built-in policies", "edit"))
		}
	}

	for n, st := range cfg.ServiceTemplates {
		if stat := checkServiceTemplate(n, st, cfg, vopts); stat != nil {
			return stat
		}
	}

	for n, res := range cfg.Resources {
		if err := checkName(n); err != nil {
			return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgResources, n), err.Error())
		}
		for i, item := range res.Clients {
			if _, ok := cfg.Clients[item]; !ok {
				return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgResources, n, "clients", strconv.Itoa(i)), fmt.Sprintf("client %q does not exist", item))
			}
		}
		if len(res.MaxTokenTtl) > 0 && !ttlRE.Match([]byte(res.MaxTokenTtl)) {
			return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgResources, n, "maxTokenTtl"), "max token TTL invalid format")
		}
		for vn, view := range res.Views {
			if stat := checkViewIntegrity(vn, view, n, res, cfg, vopts); stat != nil {
				return stat
			}
		}
		if path, err := check.CheckUI(res.Ui, true); err != nil {
			return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgResources, n, path), fmt.Sprintf("resource UI settings: %v", err))
		}
	}

	for n, cl := range cfg.Clients {
		if err := oathclients.CheckClientIntegrity(n, cl); err != nil {
			return status.Convert(err)
		}
	}

	for n, def := range cfg.VisaTypes {
		if path, err := check.CheckUI(def.Ui, true); err != nil {
			return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgVisaTypes, n, path), fmt.Sprintf("claim definitions UI settings: %v", err))
		}
	}

	personaEmail := make(map[string]string)
	for n, tp := range cfg.TestPersonas {
		if err := checkName(n); err != nil {
			return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgTestPersonas, n), err.Error())
		}
		if tp.Passport == nil {
			return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgTestPersonas, n, "passport"), "persona requires a passport")
		}
		tid, err := persona.ToIdentity(context.Background(), n, tp, defaultPersonaScope, "")
		if err != nil {
			return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgTestPersonas, n), fmt.Sprintf("persona to identity: %v", err))
		}
		if len(tid.Issuer) == 0 {
			return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgTestPersonas, n, "passport", "standardClaims", "iss"), "persona requires an issuer")
		}
		if len(tid.Subject) == 0 {
			return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgTestPersonas, n, "passport", "standardClaims", "sub"), "persona requires a subject")
		}
		if pmatch, ok := personaEmail[tid.Subject]; ok {
			return httputils.NewInfoStatus(codes.AlreadyExists, httputils.StatusPath(cfgTestPersonas, n, "passport", "standardClaims", "sub"), fmt.Sprintf("persona subject %q conflicts with test persona %q", tid.Subject, pmatch))
		}
		for i, a := range tp.Passport.Ga4GhAssertions {
			// Test Persona conditions should meet the same criteria as policies that have no variables / arguments.
			policy := &pb.Policy{
				AnyOf: a.AnyOfConditions,
			}
			if path, err := validator.ValidatePolicy(policy, cfg.VisaTypes, cfg.TrustedSources, nil); err != nil {
				path = strings.Replace(path, "anyOf/", "anyOfConditions/", 1)
				return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgTestPersonas, n, "passport", "ga4ghAssertions", strconv.Itoa(i), path), err.Error())
			}
		}
		if path, err := check.CheckUI(tp.Ui, false); err != nil {
			return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgTestPersonas, n, path), fmt.Sprintf("test persona UI settings: %v", err))
		}
		// Checking persona expectations is in checkExtraIntegrity() to give an
		// opportunity for runTests() to catch problems and calculate a ConfigModification
		// response.
	}

	if stat := checkOptionsIntegrity(cfg.Options, vopts); stat != nil {
		return stat
	}

	if path, err := check.CheckUI(cfg.Ui, true); err != nil {
		return httputils.NewInfoStatus(codes.InvalidArgument, httputils.StatusPath(cfgRoot, path), fmt.Sprintf("root config UI settings: %v", err))
	}

	return nil
}