View Javadoc
1   package org.argeo.ident;
2   
3   import java.io.BufferedReader;
4   import java.io.IOException;
5   import java.io.InputStreamReader;
6   import java.io.OutputStream;
7   import java.net.ConnectException;
8   import java.net.Socket;
9   import java.nio.charset.StandardCharsets;
10  import java.nio.file.Files;
11  import java.nio.file.Path;
12  import java.nio.file.Paths;
13  import java.util.List;
14  import java.util.StringTokenizer;
15  
16  /**
17   * A simple ident client, supporting authd OpenSSL encrypted username.
18   * 
19   * @see RFC 1413 https://tools.ietf.org/html/rfc1413
20   */
21  public class IdentClient {
22  	public final static int DEFAULT_IDENT_PORT = 113;
23  	public final static String AUTHD_PASSPHRASE_PATH = "/etc/ident.key";
24  	final static String NO_USER = "NO-USER";
25  
26  	private final String host;
27  	private final int port;
28  
29  	private OpenSslDecryptor openSslDecryptor = new OpenSslDecryptor();
30  	private String identPassphrase = null;
31  
32  	public IdentClient(String host) {
33  		this(host, readPassphrase(AUTHD_PASSPHRASE_PATH), DEFAULT_IDENT_PORT);
34  	}
35  
36  	public IdentClient(String host, Path passPhrasePath) {
37  		this(host, readPassphrase(passPhrasePath), DEFAULT_IDENT_PORT);
38  	}
39  
40  	public IdentClient(String host, String identPassphrase) {
41  		this(host, identPassphrase, DEFAULT_IDENT_PORT);
42  	}
43  
44  	public IdentClient(String host, String identPassphrase, int port) {
45  		this.host = host;
46  		this.identPassphrase = identPassphrase;
47  		this.port = port;
48  	}
49  
50  	/** @return the username or null if none */
51  	public String getUsername(int serverPort, int clientPort) {
52  		String answer;
53  		try (Socket socket = new Socket(host, port)) {
54  			String msg = clientPort + "," + serverPort + "\n";
55  			OutputStream out = socket.getOutputStream();
56  			out.write(msg.getBytes(StandardCharsets.US_ASCII));
57  			out.flush();
58  			BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
59  			answer = reader.readLine();
60  		} catch (ConnectException e) {
61  			System.err.println(
62  					"Ident client is configured but no ident server available on " + host + " (port " + port + ")");
63  			return null;
64  		} catch (Exception e) {
65  			throw new RuntimeException("Cannot read from ident server on " + host + " (port " + port + ")", e);
66  		}
67  		StringTokenizer st = new StringTokenizer(answer, " :\n");
68  		String username = null;
69  		while (st.hasMoreTokens())
70  			username = st.nextToken();
71  
72  		if (username.equals(NO_USER))
73  			return null;
74  
75  		if (identPassphrase != null && username.startsWith("[")) {
76  			String encrypted = username.substring(1, username.length() - 1);
77  			username = openSslDecryptor.decryptAuthd(encrypted, identPassphrase).trim();
78  		}
79  //		System.out.println(username);
80  		return username;
81  	}
82  
83  	public void setOpenSslDecryptor(OpenSslDecryptor openSslDecryptor) {
84  		this.openSslDecryptor = openSslDecryptor;
85  	}
86  
87  	public static String readPassphrase(String filePath) {
88  		return readPassphrase(Paths.get(filePath));
89  	}
90  
91  	/** @return the first line of the file. */
92  	public static String readPassphrase(Path path) {
93  		if (!isPathAvailable(path))
94  			return null;
95  		List<String> lines;
96  		try {
97  			lines = Files.readAllLines(path);
98  		} catch (IOException e) {
99  			throw new IllegalStateException("Cannot read " + path, e);
100 		}
101 		if (lines.size() == 0)
102 			return null;
103 		String passphrase = lines.get(0);
104 		return passphrase;
105 	}
106 
107 	public static boolean isDefaultAuthdPassphraseFileAvailable() {
108 		return isPathAvailable(Paths.get(AUTHD_PASSPHRASE_PATH));
109 	}
110 
111 	public static boolean isPathAvailable(Path path) {
112 		if (!Files.exists(path))
113 			return false;
114 		if (!Files.isReadable(path))
115 			return false;
116 		return true;
117 	}
118 
119 	public static void main(String[] args) {
120 		IdentClient identClient = new IdentClient("127.0.0.1", "changeit");
121 		String username = identClient.getUsername(7070, 55958);
122 		System.out.println(username);
123 	}
124 }