private void doAuthentication(PGStream pgStream, String user, String password, Logger logger)
      throws IOException, SQLException {
    // Now get the response from the backend, either an error message
    // or an authentication request

    while (true) {
      int beresp = pgStream.ReceiveChar();

      switch (beresp) {
        case 'E':
          // An error occured, so pass the error message to the
          // user.
          //
          // The most common one to be thrown here is:
          // "User authentication failed"
          //
          int l_elen = pgStream.ReceiveInteger4();
          if (l_elen > 30000) {
            // if the error length is > than 30000 we assume this is really a v2 protocol
            // server, so trigger fallback.
            throw new UnsupportedProtocolException();
          }

          ServerErrorMessage errorMsg =
              new ServerErrorMessage(pgStream.ReceiveString(l_elen - 4), logger.getLogLevel());
          if (logger.logDebug()) logger.debug(" <=BE ErrorMessage(" + errorMsg + ")");
          throw new PSQLException(errorMsg);

        case 'R':
          // Authentication request.
          // Get the message length
          int l_msgLen = pgStream.ReceiveInteger4();

          // Get the type of request
          int areq = pgStream.ReceiveInteger4();

          // Process the request.
          switch (areq) {
            case AUTH_REQ_CRYPT:
              {
                byte[] rst = new byte[2];
                rst[0] = (byte) pgStream.ReceiveChar();
                rst[1] = (byte) pgStream.ReceiveChar();
                String salt = new String(rst, 0, 2, "US-ASCII");

                if (logger.logDebug())
                  logger.debug(" <=BE AuthenticationReqCrypt(salt='" + salt + "')");

                if (password == null)
                  throw new PSQLException(
                      GT.tr(
                          "The server requested password-based authentication, but no password was provided."),
                      PSQLState.CONNECTION_REJECTED);

                String result = UnixCrypt.crypt(salt, password);
                byte[] encodedResult = result.getBytes("US-ASCII");

                if (logger.logDebug()) logger.debug(" FE=> Password(crypt='" + result + "')");

                pgStream.SendChar('p');
                pgStream.SendInteger4(4 + encodedResult.length + 1);
                pgStream.Send(encodedResult);
                pgStream.SendChar(0);
                pgStream.flush();

                break;
              }

            case AUTH_REQ_MD5:
              {
                byte[] md5Salt = pgStream.Receive(4);
                if (logger.logDebug()) {
                  logger.debug(
                      " <=BE AuthenticationReqMD5(salt=" + Utils.toHexString(md5Salt) + ")");
                }

                if (password == null)
                  throw new PSQLException(
                      GT.tr(
                          "The server requested password-based authentication, but no password was provided."),
                      PSQLState.CONNECTION_REJECTED);

                byte[] digest = MD5Digest.encode(user, password, md5Salt);

                if (logger.logDebug()) {
                  logger.debug(" FE=> Password(md5digest=" + new String(digest, "US-ASCII") + ")");
                }

                pgStream.SendChar('p');
                pgStream.SendInteger4(4 + digest.length + 1);
                pgStream.Send(digest);
                pgStream.SendChar(0);
                pgStream.flush();

                break;
              }

            case AUTH_REQ_PASSWORD:
              {
                if (logger.logDebug()) {
                  logger.debug(" <=BE AuthenticationReqPassword");
                  logger.debug(" FE=> Password(password=<not shown>)");
                }

                if (password == null)
                  throw new PSQLException(
                      GT.tr(
                          "The server requested password-based authentication, but no password was provided."),
                      PSQLState.CONNECTION_REJECTED);

                byte[] encodedPassword = password.getBytes("US-ASCII");

                pgStream.SendChar('p');
                pgStream.SendInteger4(4 + encodedPassword.length + 1);
                pgStream.Send(encodedPassword);
                pgStream.SendChar(0);
                pgStream.flush();

                break;
              }

            case AUTH_REQ_OK:
              if (logger.logDebug()) logger.debug(" <=BE AuthenticationOk");

              return; // We're done.

            default:
              if (logger.logDebug())
                logger.debug(" <=BE AuthenticationReq (unsupported type " + ((int) areq) + ")");

              throw new PSQLException(
                  GT.tr(
                      "The authentication type {0} is not supported. Check that you have configured the pg_hba.conf file to include the client''s IP address or subnet, and that it is using an authentication scheme supported by the driver.",
                      new Integer(areq)),
                  PSQLState.CONNECTION_REJECTED);
          }

          break;

        default:
          throw new PSQLException(
              GT.tr("Protocol error.  Session setup failed."),
              PSQLState.CONNECTION_UNABLE_TO_CONNECT);
      }
    }
  }
  private void readStartupMessages(
      PGStream pgStream, ProtocolConnectionImpl protoConnection, Logger logger)
      throws IOException, SQLException {
    while (true) {
      int beresp = pgStream.ReceiveChar();
      switch (beresp) {
        case 'Z':
          // Ready For Query; we're done.
          if (pgStream.ReceiveInteger4() != 5)
            throw new IOException("unexpected length of ReadyForQuery packet");

          char tStatus = (char) pgStream.ReceiveChar();
          if (logger.logDebug()) logger.debug(" <=BE ReadyForQuery(" + tStatus + ")");

          // Update connection state.
          switch (tStatus) {
            case 'I':
              protoConnection.setTransactionState(ProtocolConnection.TRANSACTION_IDLE);
              break;
            case 'T':
              protoConnection.setTransactionState(ProtocolConnection.TRANSACTION_OPEN);
              break;
            case 'E':
              protoConnection.setTransactionState(ProtocolConnection.TRANSACTION_FAILED);
              break;
            default:
              // Huh?
              break;
          }

          return;

        case 'K':
          // BackendKeyData
          int l_msgLen = pgStream.ReceiveInteger4();
          if (l_msgLen != 12)
            throw new PSQLException(
                GT.tr("Protocol error.  Session setup failed."),
                PSQLState.CONNECTION_UNABLE_TO_CONNECT);

          int pid = pgStream.ReceiveInteger4();
          int ckey = pgStream.ReceiveInteger4();

          if (logger.logDebug())
            logger.debug(" <=BE BackendKeyData(pid=" + pid + ",ckey=" + ckey + ")");

          protoConnection.setBackendKeyData(pid, ckey);
          break;

        case 'E':
          // Error
          int l_elen = pgStream.ReceiveInteger4();
          ServerErrorMessage l_errorMsg =
              new ServerErrorMessage(pgStream.ReceiveString(l_elen - 4), logger.getLogLevel());

          if (logger.logDebug()) logger.debug(" <=BE ErrorMessage(" + l_errorMsg + ")");

          throw new PSQLException(l_errorMsg);

        case 'N':
          // Warning
          int l_nlen = pgStream.ReceiveInteger4();
          ServerErrorMessage l_warnMsg =
              new ServerErrorMessage(pgStream.ReceiveString(l_nlen - 4), logger.getLogLevel());

          if (logger.logDebug()) logger.debug(" <=BE NoticeResponse(" + l_warnMsg + ")");

          protoConnection.addWarning(new PSQLWarning(l_warnMsg));
          break;

        case 'S':
          // ParameterStatus
          int l_len = pgStream.ReceiveInteger4();
          String name = pgStream.ReceiveString();
          String value = pgStream.ReceiveString();

          if (logger.logDebug())
            logger.debug(" <=BE ParameterStatus(" + name + " = " + value + ")");

          if (name.equals("server_version")) protoConnection.setServerVersion(value);
          else if (name.equals("client_encoding")) {
            if (!value.equals("UNICODE"))
              throw new PSQLException(
                  GT.tr("Protocol error.  Session setup failed."),
                  PSQLState.CONNECTION_UNABLE_TO_CONNECT);
            pgStream.setEncoding(Encoding.getDatabaseEncoding("UNICODE"));
          } else if (name.equals("standard_conforming_strings")) {
            if (value.equals("on")) protoConnection.setStandardConformingStrings(true);
            else if (value.equals("off")) protoConnection.setStandardConformingStrings(false);
            else
              throw new PSQLException(
                  GT.tr("Protocol error.  Session setup failed."),
                  PSQLState.CONNECTION_UNABLE_TO_CONNECT);
          }

          break;

        default:
          if (logger.logDebug()) logger.debug("invalid message type=" + (char) beresp);
          throw new PSQLException(
              GT.tr("Protocol error.  Session setup failed."),
              PSQLState.CONNECTION_UNABLE_TO_CONNECT);
      }
    }
  }
Beispiel #3
0
  public Object run() {

    try {

      org.ietf.jgss.Oid desiredMechs[] = new org.ietf.jgss.Oid[1];
      desiredMechs[0] = new org.ietf.jgss.Oid("1.2.840.113554.1.2.2");

      GSSManager manager = GSSManager.getInstance();

      GSSName clientName = manager.createName(user, GSSName.NT_USER_NAME);
      GSSCredential clientCreds =
          manager.createCredential(clientName, 8 * 3600, desiredMechs, GSSCredential.INITIATE_ONLY);

      GSSName serverName =
          manager.createName(kerberosServerName + "@" + host, GSSName.NT_HOSTBASED_SERVICE);

      GSSContext secContext =
          manager.createContext(
              serverName, desiredMechs[0], clientCreds, GSSContext.DEFAULT_LIFETIME);
      secContext.requestMutualAuth(true);

      byte inToken[] = new byte[0];
      byte outToken[] = null;

      boolean established = false;
      while (!established) {
        outToken = secContext.initSecContext(inToken, 0, inToken.length);

        if (outToken != null) {
          if (logger.logDebug()) logger.debug(" FE=> Password(GSS Authentication Token)");

          pgStream.SendChar('p');
          pgStream.SendInteger4(4 + outToken.length);
          pgStream.Send(outToken);
          pgStream.flush();
        }

        if (!secContext.isEstablished()) {
          int response = pgStream.ReceiveChar();
          // Error
          if (response == 'E') {
            int l_elen = pgStream.ReceiveInteger4();
            ServerErrorMessage l_errorMsg =
                new ServerErrorMessage(pgStream.ReceiveString(l_elen - 4), logger.getLogLevel());

            if (logger.logDebug()) logger.debug(" <=BE ErrorMessage(" + l_errorMsg + ")");

            return new PSQLException(l_errorMsg);

          } else if (response == 'R') {

            if (logger.logDebug()) logger.debug(" <=BE AuthenticationGSSContinue");

            int len = pgStream.ReceiveInteger4();
            int type = pgStream.ReceiveInteger4();
            // should check type = 8
            inToken = pgStream.Receive(len - 8);
          } else {
            // Unknown/unexpected message type.
            return new PSQLException(
                GT.tr("Protocol error.  Session setup failed."),
                PSQLState.CONNECTION_UNABLE_TO_CONNECT);
          }
        } else {
          established = true;
        }
      }

    } catch (IOException e) {
      return e;
    } catch (GSSException gsse) {
      return new PSQLException(
          GT.tr("GSS Authentication failed"), PSQLState.CONNECTION_FAILURE, gsse);
    }

    return null;
  }