/** * i-net software provides programming examples for illustration only, without warranty * either expressed or implied, including, but not limited to, the implied warranties * of merchantability and/or fitness for a particular purpose. This programming example * assumes that you are familiar with the programming language being demonstrated and * the tools used to create and debug procedures. i-net software support professionals * can help explain the functionality of a particular procedure, but they will not modify * these examples to provide added functionality or construct procedures to meet your * specific needs. * * Copyright © 1999-2025 i-net software GmbH, Berlin, Germany. **/ package com.inet.authentication.passwordfile; /* either expressed or implied, including, but not limited to, the implied warranties of merchantability and/or fitness for a particular purpose. This programming example assumes that you are familiar with the programming language being demonstrated and the tools used to create and debug procedures. i-net software support professionals can help explain the functionality of a particular procedure, but they will not modify these examples to provide added functionality or construct procedures to meet your specific needs. © i-net software 1998-2017 */ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; import java.util.List; import java.util.Map; /** * It is responsible for reading data from password file defined in configuration for Password File Authentication.
* Content of the password file must be UTF-8-encoded. Each text line of the file must represent data of single * user:
*
* userName:realm:ha1
*
* where ha1 is MD5 hash value of A1 which is defined by RFC7616 as
* A1 = unq(username) ":" unq(realm) ":" passwd
*
* For example:
* bob:i-net Clear Reports:253e2ac5a9c0c3d0fc0a5092ba886cec
*/ public class PasswordFile { private String passwordFile; private Map map = new HashMap<>(); private String previousFilePath = null; private long previousLastModified = -1; /** * Set the current password file. * * @param passwordFile current file; */ void setPasswordFile( String passwordFile ) { this.passwordFile = passwordFile; } /** * Returns hash value of A1 for given user and realm or null. * * @param userName name of the user from the request. * @param realm realm from the request. * @return hash value of A1 for given user and realm or null. * @throws IOException if an I/O error occurs reading from the file or a malformed or unmappable byte sequence is * read. */ public synchronized String getHashValueOfA1( String userName, String realm ) throws IOException { try { loadData(); } catch( IOException ex ) { map.clear(); previousFilePath = null; previousLastModified = -1; throw ex; } return map.get( userName + ":" + realm ); } /** * Loads data from password file, if needed. It does nothing if path that denotes password file and its time of last * modification have not been changed since last call. * * @throws IOException if an I/O error occurs reading from the file or a malformed or unmappable byte sequence is * read. */ private void loadData() throws IOException { String filePath = passwordFile; Path passwordFile = Paths.get( filePath ); long lastModified = passwordFile.toFile().lastModified(); if( previousFilePath != null && previousFilePath.equals( filePath ) && previousLastModified == lastModified ) { return; } map.clear(); List allLines = Files.readAllLines( passwordFile, StandardCharsets.UTF_8 ); for( String line : allLines ) { int index = line.lastIndexOf( ":" ); if( index <= 0 || index == line.length() - 1 ) { continue; } String key = line.substring( 0, index ); String value = line.substring( index + 1 ); map.put( key, value ); } previousFilePath = filePath; previousLastModified = lastModified; } }