private boolean checkValidUser_digestAuthentication_processCredentials(  URI requestURI,
									     HTTPHeaders headers,
									     HypertextAccessFile htaccess,
									     String authMethod,
									     File authUserFile,
									     Map<String,BasicType> additionalSettings,
									     Map<String,BasicType> optionalReturnSettings,

									     Map<String,String> challengeMap,

									     String chl_algorithm,
									     String chl_realm,
									     String chl_response,
									     String chl_uri,
									     String chl_username,
									     String chl_nonce
									     ) 
	throws IOException,
	       MissingParamException,
	       ConfigurationException {

	
	// Calculate the final MD5 checksum (hopefully the same as specified in the htaccess file).
	// See: http://blog.smartbear.com/software-quality/bid/169684/How-to-Use-Digest-HTTP-Authentication-in-soapUI
	// ------------------------------------------------------
	// [...]
	// In the first version ( RFC 2069 ) the algorithm is:
	//
	// A1 = username:realm:password
	// A2 = method:digestURI
	// HA1 = MD5( A1 )
	// HA2 = MD5( A2 )
	// response = MD5( HA1:nonce:HA2 )
	// [...]
	// ------------------------------------------------------
	// For more details see 
	//  - http://tools.ietf.org/html/rfc2617
	// and
	//  - http://tools.ietf.org/html/rfc2069



	char[] filePassData = null;
	try {
	    filePassData = HypertextPasswordFile.getPasswordData( authUserFile, 
								  chl_username, 
								  this.strictMode );
	    // Found in file?
	    if( filePassData == null ) 
		return false;       // Not in the user list

	    // Password data exists -> store into returnSettings
	    this.storeAuthUserSettings( filePassData, optionalReturnSettings );
	    
	    
	    String[] filePassData_split = null;
	    //if( !MD5.isIKRSMD5(new String(filePassData)) ) {
	    try {

		filePassData_split = MD5.splitIKRSMD5( new String(filePassData) );


	    } catch( NumberFormatException e ) {

		this.logger.log( Level.INFO,
				 getClass().getName() + ".checkValidUser_digestAuthentication_processCredentials(...)",
				 "The hashed data from the AuthUserFile '" + authUserFile.getPath() + "' is not an IKRS-MD5 (user=" + chl_username + "): " + e.getMessage() );
		throw new ConfigurationException( "The hashed data from the AuthUserFile is not an IKRS-MD5." );

	    }

	    
	    // The splits are: { "", <identifier>, <salt>, <md5-hash> }
	    String file_salt       = filePassData_split[2];
	    String file_md5        = filePassData_split[3];



	    // The MD5 loaded from the file is already HA1:
	    //    HA1 := MD5( chl_username + ":" + chl_realm + ":" + chl_password ) = MD5( H1 )
	    // so we do not need to re-calculate anything for HA1! :)
	    // H1 is unknown here (no one wants to store plain passwords on their servers!)
	    String HA1             = file_md5;  


    	    // On Unix systems usually the password's hashes are MD5 encrypted (what about windows?)
	    MessageDigest messageDigest = MessageDigest.getInstance( chl_algorithm );
	    String A2              = headers.getRequestMethod() + ":" + chl_uri;
	    // The HA2_bytes contains 16 raw MD5 bytes (!), NOT characters!
	    byte[] HA2_bytes       = messageDigest.digest( A2.getBytes(java.nio.charset.StandardCharsets.UTF_8.name()) ); 


	    String HA2             = CustomUtil.bytes2hexString(HA2_bytes);
	    String finalHash_seed  = HA1 + ":" + chl_nonce + ":" + HA2;
	    byte[] finalHash_bytes = messageDigest.digest( finalHash_seed.getBytes(java.nio.charset.StandardCharsets.UTF_8.name()) );
	    String finalHash       = CustomUtil.bytes2hexString(finalHash_bytes);


	    
	    // Now: compare both hashes
	    try {

		this.logger.log( Level.INFO,
				 getClass().getName() + ".checkValidUser_digestAuthentication_processCredentials(...)",
				 "Going to compare hashes/response; HA1=" + HA1 + ", A2="+ A2 + ", HA2=" + HA2 + ", finalHash_seed=" + finalHash_seed + ", finalHash=" + finalHash );

		byte[] response_bytes = CustomUtil.hex2bytes( chl_response );

		boolean equal = java.util.Arrays.equals( response_bytes, finalHash_bytes );

		this.logger.log( Level.INFO,
				 getClass().getName() + ".checkValidUser_digestAuthentication_processCredentials(...)",
				 "chl_response=" + chl_response + ", finalHash=" + finalHash + ", equal=" + equal );
		

		return equal;

	    } catch( NumberFormatException e ) {

		// The passed response (from the client!) seems NOT to be a valid MD5 checksum.
		this.logger.log( Level.INFO,
			     getClass().getName() + ".checkValidUser_digestAuthentication_processCredentials(...)",
			     "The passed response (from the client!) seems NOT to be a valid MD5 checksum: " + chl_response );

		// Auth failed.
		return false; 

	    }

	    


	} catch( IOException e ) {

	    this.logger.log( Level.SEVERE,
			     getClass().getName() + ".checkValidUser_digestAuthentication_processCredentials(...)",
			     "[IOException] " + e.getMessage() );
	    throw e;

	} catch( ParseException e ) {

	    this.logger.log( Level.WARNING,
			     getClass().getName() + ".checkValidUser_digestAuthentication_processCredentials(...)",
			     "Cannot verify user. Malformed AuthUserFile: " + e.getMessage() );
	    throw new ConfigurationException( "Cannot verify user. Malformed AuthUserFile.", e );


	} catch( NoSuchAlgorithmException e ) {
	    
	    this.logger.log( Level.SEVERE,
			     getClass().getName() + ".checkValidUser_digestAuthentication_processCredentials(...)",
			     "[NoSuchAlgorithmException] Failed to retrieve hashing algorithm '" + chl_algorithm +"': " + e.getMessage() );
	    throw new ConfigurationException( "Failed to retrieve hashing algorithm '" + chl_algorithm + "'." );
	    
	} 
	
    }