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
}