Better error handling in htpasswd

CSP handling is now separate, and the MQ return codes are tidied up.
Also added defaultIdentityTest to JMS tests and fixed copyright dates for htpasswd code
This commit is contained in:
Arthur Barr
2021-01-07 11:10:20 +00:00
committed by Arthur J Barr
parent 76070234d4
commit a24258834e
16 changed files with 218 additions and 129 deletions

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2020
© Copyright IBM Corporation 2021
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@ limitations under the License.
#include <stdlib.h>
#include <string.h>
#include "log.h"
#include "htpass.h"
#include <linux/limits.h>
#include <apr_general.h>
#include <apr_errno.h>
@@ -51,9 +52,6 @@ bool htpass_valid_file(char *filename)
valid = false;
break;
}
else {
}
}
fclose(fp);
if (line)
@@ -106,12 +104,13 @@ char *find_hash(char *filename, char *user)
return hash;
}
bool htpass_authenticate_user(char *filename, char *user, char *password)
int htpass_authenticate_user(char *filename, char *user, char *password)
{
char *hash = find_hash(filename, user);
bool result = false;
int result = -1;
if (hash == NULL)
{
result = HTPASS_INVALID_USER;
log_debugf("User does not exist. user=%s", user);
}
else
@@ -122,11 +121,12 @@ bool htpass_authenticate_user(char *filename, char *user, char *password)
// status is usually either APR_SUCCESS or APR_EMISMATCH
if (status == APR_SUCCESS)
{
result = true;
result = HTPASS_VALID;
log_debugf("Correct password supplied. user=%s", user);
}
else
{
result = HTPASS_INVALID_PASSWORD;
log_debugf("Incorrect password supplied. user=%s", user);
}
}

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2020
© Copyright IBM Corporation 2021
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -17,6 +17,10 @@ limitations under the License.
#ifndef _HTPASS_H
#define _HTPASS_H
#define HTPASS_VALID 0
#define HTPASS_INVALID_USER 1
#define HTPASS_INVALID_PASSWORD 2
/**
* Validate an HTPasswd file for use with IBM MQ.
*
@@ -30,8 +34,9 @@ _Bool htpass_valid_file(char *filename);
* @param filename the HTPasswd file
* @param user the user name to authenticate
* @param password the password of the user
* @return HTPASS_VALID, HTPASS_INVALID_USER or HTPASS_INVALID_PASSWORD
*/
_Bool htpass_authenticate_user(char *filename, char *user, char *password);
int htpass_authenticate_user(char *filename, char *user, char *password);
/**
* Validate that a user exists in the password file.

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2020
© Copyright IBM Corporation 2021
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -65,9 +65,9 @@ void test_htpass_valid_file_too_long()
void test_htpass_authenticate_user_fred_valid()
{
test_start();
int ok = htpass_authenticate_user("./src/htpass_test.htpasswd", "fred", "passw0rd");
printf("%s: fred - %d\n", __func__, ok);
if (!ok)
int rc = htpass_authenticate_user("./src/htpass_test.htpasswd", "fred", "passw0rd");
printf("%s: fred - %d\n", __func__, rc);
if (rc != HTPASS_VALID)
test_fail(__func__);
test_pass();
}
@@ -75,9 +75,9 @@ void test_htpass_authenticate_user_fred_valid()
void test_htpass_authenticate_user_fred_invalid1()
{
test_start();
int ok = htpass_authenticate_user("./src/htpass_test.htpasswd", "fred", "passw0rd ");
printf("%s: fred - %d\n", __func__, ok);
if (ok)
int rc = htpass_authenticate_user("./src/htpass_test.htpasswd", "fred", "passw0rd ");
printf("%s: fred - %d\n", __func__, rc);
if (rc != HTPASS_INVALID_PASSWORD)
test_fail(__func__);
test_pass();
}
@@ -85,9 +85,9 @@ void test_htpass_authenticate_user_fred_invalid1()
void test_htpass_authenticate_user_fred_invalid2()
{
test_start();
int ok = htpass_authenticate_user("./src/htpass_test.htpasswd", "fred", "");
printf("%s: fred - %d\n", __func__, ok);
if (ok)
int rc = htpass_authenticate_user("./src/htpass_test.htpasswd", "fred", "");
printf("%s: fred - %d\n", __func__, rc);
if (rc != HTPASS_INVALID_PASSWORD)
test_fail(__func__);
test_pass();
}
@@ -95,9 +95,9 @@ void test_htpass_authenticate_user_fred_invalid2()
void test_htpass_authenticate_user_fred_invalid3()
{
test_start();
int ok = htpass_authenticate_user("./src/htpass_test.htpasswd", "fred", "clearlywrong");
printf("%s: fred - %d\n", __func__, ok);
if (ok)
int rc = htpass_authenticate_user("./src/htpass_test.htpasswd", "fred", "clearlywrong");
printf("%s: fred - %d\n", __func__, rc);
if (rc != HTPASS_INVALID_PASSWORD)
test_fail(__func__);
test_pass();
}
@@ -105,9 +105,19 @@ void test_htpass_authenticate_user_fred_invalid3()
void test_htpass_authenticate_user_barney_valid()
{
test_start();
int ok = htpass_authenticate_user("./src/htpass_test.htpasswd", "barney", "s3cret");
printf("%s: barney - %d\n", __func__, ok);
if (!ok)
int rc = htpass_authenticate_user("./src/htpass_test.htpasswd", "barney", "s3cret");
printf("%s: barney - %d\n", __func__, rc);
if (rc != HTPASS_VALID)
test_fail(__func__);
test_pass();
}
void test_htpass_authenticate_user_unknown()
{
test_start();
int rc = htpass_authenticate_user("./src/htpass_test.htpasswd", "george", "s3cret");
printf("%s: barney - %d\n", __func__, rc);
if (rc != HTPASS_INVALID_USER)
test_fail(__func__);
test_pass();
}
@@ -127,11 +137,11 @@ void *authenticate_many_times(void *p)
{
for (int i = 0; i < NUM_TESTS_PER_THREAD; i++)
{
int ok = htpass_authenticate_user("./src/htpass_test.htpasswd", "barney", "s3cret");
if (!ok)
int rc = htpass_authenticate_user("./src/htpass_test.htpasswd", "barney", "s3cret");
if (rc != HTPASS_VALID)
test_fail(__func__);
ok = htpass_authenticate_user("./src/htpass_test.htpasswd", "fred", "passw0rd");
if (!ok)
rc = htpass_authenticate_user("./src/htpass_test.htpasswd", "fred", "passw0rd");
if (rc != HTPASS_VALID)
test_fail(__func__);
}
pthread_exit(NULL);
@@ -205,6 +215,7 @@ int main()
test_htpass_authenticate_user_fred_invalid2();
test_htpass_authenticate_user_fred_invalid3();
test_htpass_authenticate_user_barney_valid();
test_htpass_authenticate_user_unknown();
log_close();
// Call multi-threaded test last, because it re-initializes the log to use a file

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2020
© Copyright IBM Corporation 2021
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2020
© Copyright IBM Corporation 2021
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@@ -1,5 +1,5 @@
/*
© Copyright IBM Corporation 2020
© Copyright IBM Corporation 2021
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -111,8 +111,109 @@ void MQENTRY MQStart(
return;
}
/**
* Called during the connection of any application which supplies an MQCSP (Connection Security Parameters).
* This is the usual case.
* See https://www.ibm.com/support/knowledgecenter/SSFKSJ_latest/com.ibm.mq.ref.dev.doc/q095610_.html
*/
static void MQENTRY mqhtpass_authenticate_user_csp(
PMQCHAR pQMgrName,
PMQCSP pSecurityParms,
PMQZAC pApplicationContext,
PMQZIC pIdentityContext,
PMQPTR pCorrelationPtr,
PMQBYTE pComponentData,
PMQLONG pContinuation,
PMQLONG pCompCode,
PMQLONG pReason)
{
char *csp_user = NULL;
char *csp_pass = NULL;
// Firstly, create null-terminated strings from the user credentials in the MQ CSP object
csp_user = malloc(pSecurityParms->CSPUserIdLength + 1);
if (!csp_user)
{
log_errorf("%s is unable to allocate memory for a user", NAME);
*pCompCode = MQCC_FAILED;
*pReason = MQRC_SERVICE_ERROR;
return;
}
strncpy(csp_user, pSecurityParms->CSPUserIdPtr, pSecurityParms->CSPUserIdLength);
csp_user[pSecurityParms->CSPUserIdLength] = 0;
csp_pass = malloc((pSecurityParms->CSPPasswordLength + 1));
if (!csp_pass)
{
log_errorf("%s is unable to allocate memory for a password", NAME);
*pCompCode = MQCC_FAILED;
*pReason = MQRC_SERVICE_ERROR;
if (csp_user)
{
free(csp_user);
}
return;
}
strncpy(csp_pass, pSecurityParms->CSPPasswordPtr, pSecurityParms->CSPPasswordLength);
csp_pass[pSecurityParms->CSPPasswordLength] = 0;
log_debugf("%s with CSP user set. user=%s", __func__, csp_user);
int auth_result = htpass_authenticate_user(HTPASSWD_FILE, csp_user, csp_pass);
if (auth_result == HTPASS_VALID)
{
// An OK completion code means MQ will accept this user is authenticated
*pCompCode = MQCC_OK;
*pReason = MQRC_NONE;
// Tell the queue manager to stop trying other authorization services.
*pContinuation = MQZCI_STOP;
memcpy(pIdentityContext->UserIdentifier, csp_user, sizeof(pIdentityContext->UserIdentifier));
log_debugf("Authenticated user=%s", pIdentityContext->UserIdentifier);
}
// If the htpasswd file does not have an entry for this user
else if (auth_result == HTPASS_INVALID_USER)
{
*pCompCode = MQCC_WARNING;
*pReason = MQRC_NONE;
// Tell the queue manager to continue trying other authorization services, as they might have the user.
*pContinuation = MQZCI_CONTINUE;
log_debugf(
"User authentication failed due to invalid user. user=%s effuser=%s applname=%s csp_user=%s cc=%d reason=%d",
trim(pIdentityContext->UserIdentifier),
trim(pApplicationContext->EffectiveUserID),
trim(pApplicationContext->ApplName),
trim(csp_user),
*pCompCode,
*pReason);
}
// If the htpasswd file has an entry for this user, but the password supplied is incorrect
else if (auth_result == HTPASS_INVALID_PASSWORD)
{
*pCompCode = MQCC_WARNING;
*pReason = MQRC_NOT_AUTHORIZED;
// Tell the queue manager to stop trying other authorization services.
*pContinuation = MQZCI_STOP;
log_debugf(
"User authentication failed due to invalid password. user=%s effuser=%s applname=%s csp_user=%s cc=%d reason=%d",
trim(pIdentityContext->UserIdentifier),
trim(pApplicationContext->EffectiveUserID),
trim(pApplicationContext->ApplName),
trim(csp_user),
*pCompCode,
*pReason);
}
if (csp_user)
{
free(csp_user);
}
if (csp_pass)
{
free(csp_pass);
}
return;
}
/**
* Called during the connection of any application.
* For more information on the parameters, see https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_latest/com.ibm.mq.ref.dev.doc/q110090_.html
*/
static void MQENTRY mqhtpass_authenticate_user(
PMQCHAR pQMgrName,
@@ -137,59 +238,7 @@ static void MQENTRY mqhtpass_authenticate_user(
if ((pSecurityParms->AuthenticationType) == MQCSP_AUTH_USER_ID_AND_PWD)
{
// Authenticating a user ID and password.
// Firstly, create null-terminated strings from the user credentials in the MQ CSP object
spuser = malloc(pSecurityParms->CSPUserIdLength + 1);
if (!spuser)
{
log_errorf("%s is unable to allocate memory for a user", NAME);
return;
}
strncpy(spuser, pSecurityParms->CSPUserIdPtr, pSecurityParms->CSPUserIdLength);
spuser[pSecurityParms->CSPUserIdLength] = 0;
sppass = malloc((pSecurityParms->CSPPasswordLength + 1));
if (!sppass)
{
log_errorf("%s is unable to allocate memory for a password", NAME);
if (spuser)
{
free(spuser);
}
return;
}
strncpy(sppass, pSecurityParms->CSPPasswordPtr, pSecurityParms->CSPPasswordLength);
sppass[pSecurityParms->CSPPasswordLength] = 0;
log_debugf("%s with CSP user set. user=%s", __func__, spuser);
bool authenticated = htpass_authenticate_user(HTPASSWD_FILE, spuser, sppass);
if (authenticated)
{
*pCompCode = MQCC_OK;
*pReason = MQRC_NONE;
*pContinuation = MQZCI_CONTINUE;
memcpy(pIdentityContext->UserIdentifier, spuser, sizeof(pIdentityContext->UserIdentifier));
log_debugf("Authenticated user=%s", pIdentityContext->UserIdentifier);
}
else
{
log_debugf(
"User authentication failed user=%s effuser=%s applname=%s cspuser=%s cc=%d reason=%d",
trim(pIdentityContext->UserIdentifier),
trim(pApplicationContext->EffectiveUserID),
trim(pApplicationContext->ApplName),
trim(spuser),
*pCompCode,
*pReason);
}
if (spuser)
{
free(spuser);
}
if (sppass)
{
free(sppass);
}
mqhtpass_authenticate_user_csp(pQMgrName, pSecurityParms, pApplicationContext, pIdentityContext, pCorrelationPtr, pComponentData, pContinuation, pCompCode, pReason);
}
else
{
@@ -198,6 +247,8 @@ static void MQENTRY mqhtpass_authenticate_user(
if (!spuser)
{
log_errorf("%s is unable to allocate memory to check a user", NAME);
*pCompCode = MQCC_FAILED;
*pReason = MQRC_SERVICE_ERROR;
return;
}
strncpy(spuser, pApplicationContext->EffectiveUserID, strlen(pApplicationContext->EffectiveUserID));
@@ -219,7 +270,7 @@ static void MQENTRY mqhtpass_authenticate_user(
// An OK completion code means MQ will accept this user is authenticated
*pCompCode = MQCC_OK;
*pReason = MQRC_NONE;
*pContinuation = MQZCI_CONTINUE;
*pContinuation = MQZCI_STOP;
memcpy(pIdentityContext->UserIdentifier, spuser, sizeof(pIdentityContext->UserIdentifier));
}
else