func()

in lib/dam/token_flow.go [235:367]


func (s *Service) auth(ctx context.Context, in authHandlerIn) (_ *authHandlerOut, ferr error) {
	tx, err := s.store.Tx(true)
	if err != nil {
		return nil, status.Errorf(codes.Unavailable, err.Error())
	}
	defer func() {
		err := tx.Finish()
		if ferr == nil && err != nil {
			ferr = status.Errorf(codes.Unavailable, err.Error())
		}
	}()

	sec, err := s.loadSecrets(tx)
	if err != nil {
		return nil, status.Errorf(codes.Unavailable, err.Error())
	}

	realm := in.realm
	if in.tokenType == pb.ResourceTokenRequestState_DATASET {
		if len(in.resources) == 0 {
			return nil, status.Errorf(codes.FailedPrecondition, "empty resource list")
		}
		realm = in.resources[0].realm
	}

	cfg, err := s.loadConfig(tx, realm)
	if err != nil {
		return nil, status.Errorf(codes.Unavailable, err.Error())
	}

	broker, ok := cfg.TrustedIssuers[s.defaultBroker]
	if !ok {
		return nil, status.Errorf(codes.InvalidArgument, "broker %q is not defined", s.defaultBroker)
	}
	clientSecret, ok := sec.GetBrokerSecrets()[broker.ClientId]
	if !ok {
		return nil, status.Errorf(codes.FailedPrecondition, "client secret of broker %q is not defined", s.defaultBroker)
	}

	var list []*pb.ResourceTokenRequestState_Resource

	for _, rvr := range in.resources {
		if rvr.realm != realm {
			return nil, status.Errorf(codes.Aborted, "cannot authorize resources using different realms")
		}

		resName := rvr.resource
		viewName := rvr.view
		roleName := rvr.role
		interf := rvr.interf
		if err := checkName(resName); err != nil {
			return nil, status.Errorf(codes.InvalidArgument, err.Error())
		}
		if err := checkName(viewName); err != nil {
			return nil, status.Errorf(codes.InvalidArgument, err.Error())
		}

		res, ok := cfg.Resources[resName]
		if !ok {
			return nil, status.Errorf(codes.NotFound, "resource not found: %q", resName)
		}
		view, ok := res.Views[viewName]
		if !ok {
			return nil, status.Errorf(codes.NotFound, "view %q not found for resource %q", viewName, resName)
		}
		grantRole := roleName
		if len(grantRole) == 0 {
			grantRole = view.DefaultRole
		}
		if !viewHasRole(view, grantRole) {
			return nil, status.Errorf(codes.FailedPrecondition, "role %q is not defined on resource %q view %q", grantRole, resName, viewName)
		}
		st, ok := cfg.ServiceTemplates[view.ServiceTemplate]
		if !ok {
			return nil, status.Errorf(codes.Internal, "service template %q is invalid for resource %q view %q", view.ServiceTemplate, resName, viewName)
		}
		// TODO: remove support for oldResourcePath
		if len(interf) == 0 {
			for k := range st.Interfaces {
				interf = k
				break
			}
		}
		if _, ok = st.Interfaces[interf]; !ok {
			return nil, status.Errorf(codes.FailedPrecondition, "interface %q is not defined on resource %q view %q service template %q", interf, resName, viewName, view.ServiceTemplate)
		}

		list = append(list, &pb.ResourceTokenRequestState_Resource{
			Realm:     rvr.realm,
			Resource:  resName,
			View:      viewName,
			Role:      grantRole,
			Interface: interf,
			Url:       rvr.url,
		})
	}

	// TODO: need support real policy filter
	scopes := []string{"openid", "ga4gh_passport_v1", "identities", "account_admin"}
	if in.tokenType == pb.ResourceTokenRequestState_ENDPOINT {
		scopes = []string{"openid", "identities"}
	}

	sID := uuid.New()

	state := &pb.ResourceTokenRequestState{
		Type:              in.tokenType,
		ClientId:          in.clientID,
		ClientName:        in.clientName,
		State:             in.stateID,
		Broker:            s.defaultBroker,
		Redirect:          in.redirect,
		Ttl:               int64(in.ttl),
		ResponseKeyFile:   in.responseKeyFile,
		Resources:         list,
		LoginChallenge:    in.challenge,
		EpochSeconds:      time.Now().Unix(),
		Realm:             realm,
		RequestedAudience: in.requestedAudience,
		RequestedScope:    in.requestedScope,
	}

	err = s.store.WriteTx(storage.ResourceTokenRequestStateDataType, storage.DefaultRealm, storage.DefaultUser, sID, storage.LatestRev, state, nil, tx)
	if err != nil {
		return nil, status.Errorf(codes.Unavailable, err.Error())
	}

	conf := s.oauthConf(s.defaultBroker, broker, clientSecret, scopes)
	return &authHandlerOut{
		oauth:   conf,
		stateID: sID,
	}, nil
}