Example #1
0
        async Task Authenticate(string username, NpgsqlTimeout timeout, bool async, CancellationToken cancellationToken)
        {
            Log.Authenticating(Id);

            var msg = await ReadExpecting <AuthenticationRequestMessage>(async);

            timeout.Check();
            switch (msg.AuthRequestType)
            {
            case AuthenticationRequestType.AuthenticationOk:
                return;

            case AuthenticationRequestType.AuthenticationCleartextPassword:
                await AuthenticateCleartext(async, cancellationToken);

                return;

            case AuthenticationRequestType.AuthenticationMD5Password:
                await AuthenticateMD5(username, ((AuthenticationMD5PasswordMessage)msg).Salt, async, cancellationToken);

                return;

            case AuthenticationRequestType.AuthenticationGSS:
            case AuthenticationRequestType.AuthenticationSSPI:
                await AuthenticateGSS(async, cancellationToken);

                return;

            case AuthenticationRequestType.AuthenticationGSSContinue:
                throw new NpgsqlException("Can't start auth cycle with AuthenticationGSSContinue");

            default:
                throw new NotSupportedException($"Authentication method not supported (Received: {msg.AuthRequestType})");
            }
        }
Example #2
0
        static async Task <AvailablePostgresTypes> LoadBackendTypes(NpgsqlConnector connector, NpgsqlTimeout timeout, bool async)
        {
            var commandTimeout = 0;  // Default to infinity

            if (timeout.IsSet)
            {
                commandTimeout = (int)timeout.TimeLeft.TotalSeconds;
                if (commandTimeout <= 0)
                {
                    throw new TimeoutException();
                }
            }

            var types = new AvailablePostgresTypes();

            using (var command = new NpgsqlCommand(connector.SupportsRangeTypes ? TypesQueryWithRange : TypesQueryWithoutRange, connector.Connection))
            {
                command.CommandTimeout           = commandTimeout;
                command.AllResultTypesAreUnknown = true;
                using (var reader = async ? await command.ExecuteReaderAsync() : command.ExecuteReader())
                {
                    while (async ? await reader.ReadAsync() : reader.Read())
                    {
                        timeout.Check();
                        LoadBackendType(reader, types, connector);
                    }
                }
            }
            return(types);
        }
Example #3
0
        async Task Authenticate(string username, NpgsqlTimeout timeout, bool async)
        {
            Log.Trace("Authenticating...", Id);

            var msg = Expect <AuthenticationRequestMessage>(await ReadMessage(async), this);

            timeout.Check();
            switch (msg.AuthRequestType)
            {
            case AuthenticationRequestType.AuthenticationOk:
                return;

            case AuthenticationRequestType.AuthenticationCleartextPassword:
                await AuthenticateCleartext(username, async);

                return;

            case AuthenticationRequestType.AuthenticationMD5Password:
                await AuthenticateMD5(username, ((AuthenticationMD5PasswordMessage)msg).Salt, async);

                return;

            case AuthenticationRequestType.AuthenticationSASL:
                await AuthenticateSASL(((AuthenticationSASLMessage)msg).Mechanisms, username, async);

                return;

            case AuthenticationRequestType.AuthenticationGSS:
            case AuthenticationRequestType.AuthenticationSSPI:
                await AuthenticateGSS(async);

                return;

            case AuthenticationRequestType.AuthenticationGSSContinue:
                throw new NpgsqlException("Can't start auth cycle with AuthenticationGSSContinue");

            default:
                throw new NotSupportedException($"Authentication method not supported (Received: {msg.AuthRequestType})");
            }
        }
Example #4
0
        /// <summary>
        /// Called exactly once per multiplexing pool, when the first connection is opened, with two goals:
        /// 1. Load types and bind the pool-wide type mapper (necessary for binding parameters)
        /// 2. Cause any connection exceptions (e.g. bad username) to be thrown from NpgsqlConnection.Open
        /// </summary>
        internal async Task BootstrapMultiplexing(NpgsqlConnection conn, NpgsqlTimeout timeout, bool async, CancellationToken cancellationToken = default)
        {
            Debug.Assert(_multiplexing);

            var hasSemaphore = async
                ? await _bootstrapSemaphore !.WaitAsync(timeout.TimeLeft, cancellationToken)
                : _bootstrapSemaphore !.Wait(timeout.TimeLeft, cancellationToken);

            // We've timed out - calling Check, to throw the correct exception
            if (!hasSemaphore)
            {
                timeout.Check();
            }

            try
            {
                if (IsBootstrapped)
                {
                    return;
                }

                var connector = await conn.StartBindingScope(ConnectorBindingScope.Connection, timeout, async, cancellationToken);

                using var _ = Defer(() => conn.EndBindingScope(ConnectorBindingScope.Connection));

                // Somewhat hacky. Extract the connector's type mapper as our pool-wide mapper,
                // and have the connector rebind to ensure it has a different instance.
                // The latter isn't strictly necessary (type mappers should always be usable
                // concurrently) but just in case.
                MultiplexingTypeMapper = connector.TypeMapper;
                connector.RebindTypeMapper();

                IsBootstrapped = true;
            }
            finally
            {
                _bootstrapSemaphore !.Release();
            }
        }
        /// <summary>
        /// Called exactly once per multiplexing pool, when the first connection is opened, with two goals:
        /// 1. Load types and bind the pool-wide type mapper (necessary for binding parameters)
        /// 2. Cause any connection exceptions (e.g. bad username) to be thrown from NpgsqlConnection.Open
        /// </summary>
        internal async Task BootstrapMultiplexing(NpgsqlConnection conn, NpgsqlTimeout timeout, bool async, CancellationToken cancellationToken = default)
        {
            Debug.Assert(_multiplexing);

            var hasSemaphore = async
                ? await _bootstrapSemaphore !.WaitAsync(timeout.TimeLeft, cancellationToken)
                : _bootstrapSemaphore !.Wait(timeout.TimeLeft, cancellationToken);

            // We've timed out - calling Check, to throw the correct exception
            if (!hasSemaphore)
            {
                timeout.Check();
            }

            try
            {
                if (IsBootstrapped)
                {
                    return;
                }

                var connector = await conn.StartBindingScope(ConnectorBindingScope.Connection, timeout, async, cancellationToken);

                using var _ = Defer(static conn => conn.EndBindingScope(ConnectorBindingScope.Connection), conn);
Example #6
0
        internal async Task <List <PostgresType> > LoadBackendTypes(NpgsqlConnection conn, NpgsqlTimeout timeout, bool async)
        {
            var commandTimeout = 0;  // Default to infinity

            if (timeout.IsSet)
            {
                commandTimeout = (int)timeout.TimeLeft.TotalSeconds;
                if (commandTimeout <= 0)
                {
                    throw new TimeoutException();
                }
            }

            var typeLoadingQuery = GenerateTypesQuery(SupportsRangeTypes, SupportsEnumTypes, conn.Settings.LoadTableComposites);

            using (var command = new NpgsqlCommand(typeLoadingQuery, conn))
            {
                command.CommandTimeout           = commandTimeout;
                command.AllResultTypesAreUnknown = true;
                using (var reader = async ? await command.ExecuteReaderAsync() : command.ExecuteReader())
                {
                    var byOID = new Dictionary <uint, PostgresType>();

                    // First load the types themselves
                    while (async ? await reader.ReadAsync() : reader.Read())
                    {
                        timeout.Check();

                        var ns           = reader.GetString(reader.GetOrdinal("nspname"));
                        var internalName = reader.GetString(reader.GetOrdinal("typname"));
                        var oid          = Convert.ToUInt32(reader[reader.GetOrdinal("oid")]);

                        Debug.Assert(internalName != null);
                        Debug.Assert(oid != 0);

                        var typeChar = reader.GetString(reader.GetOrdinal("type"))[0];
                        switch (typeChar)
                        {
                        case 'b':  // Normal base type
                            var baseType = new PostgresBaseType(ns, internalName, oid);
                            byOID[baseType.OID] = baseType;
                            continue;

                        case 'a': // Array
                        {
                            var elementOID = Convert.ToUInt32(reader[reader.GetOrdinal("elemoid")]);
                            Debug.Assert(elementOID > 0);
                            if (!byOID.TryGetValue(elementOID, out var elementPostgresType))
                            {
                                Log.Trace($"Array type '{internalName}' refers to unknown element with OID {elementOID}, skipping", conn.ProcessID);
                                continue;
                            }

                            var arrayType = new PostgresArrayType(ns, internalName, oid, elementPostgresType);
                            byOID[arrayType.OID] = arrayType;
                            continue;
                        }

                        case 'r': // Range
                        {
                            var elementOID = Convert.ToUInt32(reader[reader.GetOrdinal("elemoid")]);
                            Debug.Assert(elementOID > 0);
                            if (!byOID.TryGetValue(elementOID, out var subtypePostgresType))
                            {
                                Log.Trace($"Range type '{internalName}' refers to unknown subtype with OID {elementOID}, skipping", conn.ProcessID);
                                continue;
                            }

                            var rangeType = new PostgresRangeType(ns, internalName, oid, subtypePostgresType);
                            byOID[rangeType.OID] = rangeType;
                            continue;
                        }

                        case 'e':   // Enum
                            var enumType = new PostgresEnumType(ns, internalName, oid);
                            byOID[enumType.OID] = enumType;
                            continue;

                        case 'c':   // Composite
                            // Unlike other types, we don't
                            var compositeType = new PostgresCompositeType(ns, internalName, oid);
                            byOID[compositeType.OID] = compositeType;
                            continue;

                        case 'd':   // Domain
                            var baseTypeOID = Convert.ToUInt32(reader[reader.GetOrdinal("typbasetype")]);
                            Debug.Assert(baseTypeOID > 0);
                            if (!byOID.TryGetValue(baseTypeOID, out var basePostgresType))
                            {
                                Log.Trace($"Domain type '{internalName}' refers to unknown base type with OID {baseTypeOID}, skipping", conn.ProcessID);
                                continue;
                            }
                            var domainType = new PostgresDomainType(ns, internalName, oid, basePostgresType);
                            byOID[domainType.OID] = domainType;
                            continue;

                        case 'p':   // pseudo-type (record, void)
                            // Hack this as a base type
                            goto case 'b';

                        default:
                            throw new ArgumentOutOfRangeException($"Unknown typtype for type '{internalName}' in pg_type: {typeChar}");
                        }
                    }

                    if (async)
                    {
                        await reader.NextResultAsync();
                    }
                    else
                    {
                        reader.NextResult();
                    }

                    LoadCompositeFields(reader, byOID);

                    if (SupportsEnumTypes)
                    {
                        if (async)
                        {
                            await reader.NextResultAsync();
                        }
                        else
                        {
                            reader.NextResult();
                        }

                        LoadEnumLabels(reader, byOID);
                    }

                    return(byOID.Values.ToList());
                }
            }
        }