void Proceed()

in api/src/gmsa_service.cpp [340:696]


        void Proceed( std::string krb_files_dir, CF_logger& cf_logger,
                      std::string aws_sm_secret_name )
        {
            if ( cookie.compare( CLASS_NAME_CallDataCreateKerberosArnLease ) != 0 )
            {
                return;
            }

            // Note: This code-path is only for Fargate
            std::cerr << Util::getCurrentTime() << '\t' << "INFO: CallDataCreateKerberosArnLease "
                      << this << "status: " << status_ << std::endl;

            if ( status_ == CREATE )
            {
                // Make this instance progress to the PROCESS state.
                status_ = PROCESS;

                // As part of the initial CREATE state, we *request* that the system
                // start processing RequestAddKerberosLease requests. In this request, "this" acts
                // are the tag uniquely identifying the request (so that different CallData
                // instances can serve different requests concurrently), in this case
                // the memory address of this CallData instance.

                service_->RequestAddKerberosArnLease( &add_krb_ctx_, &create_arn_krb_request_,
                                                      &create_arn_krb_responder_, cq_, cq_, this );
            }
            else if ( status_ == PROCESS )
            {
                // Spawn a new CallData instance to serve new clients while we process
                // the one for this CallData. The instance will deallocate itself as
                // part of its FINISH state.
                new CallDataCreateKerberosArnLease( service_, cq_ );
                // The actual processing.
                std::string lease_id = "";
                std::list<krb_ticket_info_t*> krb_ticket_info_list;
                std::list<krb_ticket_arn_mapping_t*> krb_ticket_arn_mapping_list;
                std::unordered_set<std::string> krb_ticket_dirs;
                std::string accessId = create_arn_krb_request_.access_key_id();
                std::string secretKey = create_arn_krb_request_.secret_access_key();
                std::string sessionToken = create_arn_krb_request_.session_token();
                std::string region = create_arn_krb_request_.region();

                std::string username = "";
                std::string password = "";
                std::string domain = "";
                std::string distinguished_name = "";
                bool isTest = false;

                std::string err_msg;
                int credspecSize = create_arn_krb_request_.credspec_arns_size();

                if ( !accessId.empty() && !secretKey.empty() && !sessionToken.empty() &&
                     !region.empty() && credspecSize > 0 )
                {
                    for ( int i = 0; i < create_arn_krb_request_.credspec_arns_size(); i++ )
                    {
                        krb_ticket_info_t* krb_ticket_info = new krb_ticket_info_t;
                        krb_ticket_arn_mapping_t* krb_ticket_arns = new krb_ticket_arn_mapping_t;

                        std::string credspecarn = create_arn_krb_request_.credspec_arns( i );
                        if ( credspecarn.empty() )
                        {
                            err_msg = "ERROR: credentialspec arn should not be empty";

                            std::cerr << Util::getCurrentTime() << '\t' << err_msg << std::endl;
                            break;
                        }

                        std::vector<std::string> results =
                            Util::split_string( create_arn_krb_request_.credspec_arns( i ), '#' );

                        if ( results.size() != 2 )
                        {
                            err_msg = "ERROR: credentialspec arn is not valid";

                            std::cerr << Util::getCurrentTime() << '\t' << err_msg << std::endl;
                            break;
                        }

                        std::vector<std::string> pathResults =
                            Util::split_string( results[1], '/' );

                        if ( pathResults.size() != 2 ||
                             contains_invalid_characters_in_credentials( results[1] ) )
                        {
                            err_msg = "ERROR: mount path is invalid";

                            std::cerr << Util::getCurrentTime() << '\t' << err_msg << std::endl;
                            break;
                        }

                        isTest = IsTestInvocationForUnitTests( results[0] );

                        if ( !isTest )
                        {

                            // get credentialspec contents:
                            Aws::Auth::AWSCredentials creds =
                                get_credentials( accessId, secretKey, sessionToken );

                            bool isObjectValid =
                                check_file_size_s3( results[0], region, creds, false );
                            if ( !isObjectValid )
                            {
                                err_msg = "ERROR: invalid object for credentialspec in s3";

                                std::cerr << Util::getCurrentTime() << '\t' << err_msg << std::endl;
                                break;
                            }
                            std::string response =
                                retrieve_credspec_from_s3( results[0], region, creds, false );

                            if ( response.empty() )
                            {
                                err_msg = "ERROR: credentialspec cannot be retrieved from s3";

                                std::cerr << Util::getCurrentTime() << '\t' << err_msg << std::endl;
                                break;
                            }
                            krb_ticket_arns->credential_spec_arn = results[0];
                            int parse_result = parse_cred_spec_domainless(
                                response, krb_ticket_info, krb_ticket_arns );
                            if ( parse_result != 0 )
                            {
                                err_msg = "ERROR: invalid credentialspec fields";
                                std::cerr << Util::getCurrentTime() << '\t' << err_msg << std::endl;
                                break;
                            }

                            // only add the ticket info if the parsing is successful
                            if ( parse_result == 0 )
                            {
                                std::string secretsArn =
                                    krb_ticket_arns->credential_domainless_user_arn;
                                if ( secretsArn.empty() )
                                {
                                    err_msg = "ERROR: invalid secrets manager arn";
                                    std::cerr << Util::getCurrentTime() << '\t' << err_msg
                                              << std::endl;
                                    break;
                                }
                                // retrieve domainless user credentials
                                std::tuple<std::string, std::string, std::string, std::string>
                                    userCreds = retrieve_credspec_from_secrets_manager(
                                        krb_ticket_arns->credential_domainless_user_arn, region,
                                        creds );

                                username = std::get<0>( userCreds );
                                password = std::get<1>( userCreds );
                                domain = std::get<2>( userCreds );
                                distinguished_name = std::get<3>( userCreds );

                                if ( isValidDomain( domain ) &&
                                     !Util::contains_invalid_characters_in_ad_account_name( username ) )
                                {
                                    if ( !username.empty() && !password.empty() &&
                                         !domain.empty() &&
                                         username.length() < INPUT_CREDENTIALS_LENGTH &&
                                         password.length() < INPUT_CREDENTIALS_LENGTH &&
                                         domain.length() < DOMAIN_LENGTH )
                                    {

                                        std::string krb_files_path =
                                            krb_files_dir + "/" + results[1];
                                        std::vector<std::string> mountpath =
                                            Util::split_string( results[1], '/' );

                                        // get taskid information
                                        lease_id = mountpath[0];

                                        krb_ticket_info->krb_file_path = krb_files_path;
                                        krb_ticket_info->domainless_user = username;
                                        krb_ticket_arns->krb_file_path = krb_files_path;
                                        krb_ticket_info->distinguished_name = distinguished_name;

                                        // handle duplicate service accounts
                                        if ( !krb_ticket_dirs.count( krb_files_path ) )
                                        {
                                            krb_ticket_dirs.insert( krb_files_path );
                                            krb_ticket_info_list.push_back( krb_ticket_info );
                                            krb_ticket_arn_mapping_list.push_back(
                                                krb_ticket_arns );
                                        }
                                        else
                                        {
                                            err_msg = "ERROR: found duplicate mount paths";
                                            std::cerr << Util::getCurrentTime() << '\t' << err_msg
                                                      << std::endl;
                                            break;
                                        }
                                    }
                                    else
                                    {
                                        err_msg =
                                            "ERROR: domainless AD user credentials is not valid/ "
                                            "credentials should not be more than 256 charaters";
                                        std::cerr << Util::getCurrentTime() << '\t' << err_msg
                                                  << std::endl;
                                        break;
                                    }
                                }
                                else
                                {
                                    err_msg = "ERROR: invalid domainName/username";
                                    std::cerr << Util::getCurrentTime() << '\t' << err_msg
                                              << std::endl;
                                    break;
                                }
                            }
                        }
                        else
                        {
                            std::string krb_files_path = krb_files_dir + "/" + results[1];
                            std::vector<std::string> mountpath =
                                Util::split_string( results[1], '/' );

                            // get taskid information
                            lease_id = mountpath[0];
                            std::filesystem::create_directories( krb_files_path );
                            std::string dummyFile = krb_files_path + "/krb5cc";
                            std::ofstream o( dummyFile );
                        }
                    }
                }
                else
                {
                    err_msg = "Error: access credentials should not be empty";
                    std::cerr << Util::getCurrentTime() << '\t' << err_msg << std::endl;
                }

                create_arn_krb_reply_.set_lease_id( lease_id );

                if ( err_msg.empty() && !isTest )
                {
                    // create the kerberos tickets for the service accounts
                    for ( auto krb_ticket : krb_ticket_info_list )
                    {
                        // invoke to get machine ticket
                        std::pair<int, std::string> status;
                        if ( username.empty() || password.empty() )
                        {
                            std::string log_message =
                                "Invalid credentials for domainless user " + username;
                            cf_logger.logger( LOG_ERR, log_message.c_str() );
                            err_msg = "ERROR: Invalid credentials for domainless user";
                            std::cerr << Util::getCurrentTime() << '\t' << err_msg << std::endl;
                            break;
                        }
                        status = Util::generate_krb_ticket_using_username_and_password(
                            domain, username, password, cf_logger );
                        if ( status.first < 0 )
                        {
                            err_msg = "ERROR :" + std::to_string( status.first ) +
                                      ": Cannot retrieve domainless user kerberos tickets";
                            std::string log_message = err_msg +
                                                      " Status: " + std::to_string( status.first ) +
                                                      " " + status.second;
                            cf_logger.logger( LOG_ERR, log_message.c_str() );
                            std::cerr << Util::getCurrentTime() << '\t' << err_msg << std::endl;
                            break;
                        }

                        std::string krb_file_path = krb_ticket->krb_file_path;
                        std::filesystem::create_directories( krb_file_path );

                        std::string krb_ccname_str = krb_ticket->krb_file_path + "/krb5cc";

                        if ( !std::filesystem::exists( krb_ccname_str ) )
                        {
                            std::ofstream file( krb_ccname_str );
                            file.close();

                            krb_ticket->krb_file_path = krb_ccname_str;
                        }

                        std::pair<int, std::string> gmsa_ticket_result =
                            fetch_gmsa_password_and_create_krb_ticket( domain, krb_ticket,
                                                                       krb_ccname_str, cf_logger );
                        if ( gmsa_ticket_result.first != 0 )
                        {
                            err_msg = "ERROR: " + std::to_string( status.first ) +
                                      ": Cannot get gMSA krb ticket";
                            std::cerr << Util::getCurrentTime() << '\t' << err_msg.c_str()
                                      << std::endl;
                            cf_logger.logger( LOG_ERR, err_msg.c_str() );
                            break;
                        }
                        else
                        {
                            std::string log_message =
                                "gMSA ticket is at " + gmsa_ticket_result.second;
                            cf_logger.logger( LOG_INFO, log_message.c_str() );
                            std::cerr << Util::getCurrentTime() << '\t'
                                      << "INFO: gMSA ticket is "
                                         "created"
                                      << std::endl;
                        }
                    }
                }
                // And we are done! Let the gRPC runtime know we've finished, using the
                // memory address of this instance as the uniquely identifying tag for
                // the event.
                if ( !err_msg.empty() && !isTest )
                {
                    secureClearString( username );
                    secureClearString( password );
                    secureClearString( accessId );
                    secureClearString( sessionToken );
                    secureClearString( secretKey );

                    // remove the directories on failure
                    for ( auto krb_ticket : krb_ticket_info_list )
                    {
                        std::filesystem::remove_all( krb_ticket->krb_file_path );
                    }
                    status_ = FINISH;
                    create_arn_krb_responder_.Finish(
                        create_arn_krb_reply_, grpc::Status( grpc::StatusCode::INTERNAL, err_msg ),
                        this );
                }
                else
                {
                    if ( !isTest )
                    {
                        for ( auto arn_mapping : krb_ticket_arn_mapping_list )
                        {
                            credentialsfetcher::KerberosTicketArnResponse krb_ticket_response;
                            krb_ticket_response.set_credspec_arns(
                                arn_mapping->credential_spec_arn );
                            krb_ticket_response.set_created_kerberos_file_paths(
                                arn_mapping->krb_file_path );
                            create_arn_krb_reply_.add_krb_ticket_response_map()->CopyFrom(
                                krb_ticket_response );
                        }

                        secureClearString( username );
                        secureClearString( password );
                        secureClearString( accessId );
                        secureClearString( sessionToken );
                        secureClearString( secretKey );
                        // write the ticket information to meta data file
                        write_meta_data_json( krb_ticket_info_list, lease_id, krb_files_dir );
                    }
                    status_ = FINISH;
                    create_arn_krb_responder_.Finish( create_arn_krb_reply_, grpc::Status::OK,
                                                      this );
                }
            }
            else
            {
                GPR_ASSERT( status_ == FINISH );
                // Once in the FINISH state, deallocate ourselves (CallData).
                delete this;
            }

            return;
        }