1 package org
.argeo
.ident
;
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
;
17 * A simple ident client, supporting authd OpenSSL encrypted username.
19 * @see RFC 1413 https://tools.ietf.org/html/rfc1413
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";
26 private final String host
;
27 private final int port
;
29 private OpenSslDecryptor openSslDecryptor
= new OpenSslDecryptor();
30 private String identPassphrase
= null;
32 public IdentClient(String host
) {
33 this(host
, readPassphrase(AUTHD_PASSPHRASE_PATH
), DEFAULT_IDENT_PORT
);
36 public IdentClient(String host
, Path passPhrasePath
) {
37 this(host
, readPassphrase(passPhrasePath
), DEFAULT_IDENT_PORT
);
40 public IdentClient(String host
, String identPassphrase
) {
41 this(host
, identPassphrase
, DEFAULT_IDENT_PORT
);
44 public IdentClient(String host
, String identPassphrase
, int port
) {
46 this.identPassphrase
= identPassphrase
;
50 /** @return the username or null if none */
51 public String
getUsername(int serverPort
, int clientPort
) {
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
));
58 BufferedReader reader
= new BufferedReader(new InputStreamReader(socket
.getInputStream()));
59 answer
= reader
.readLine();
60 } catch (ConnectException e
) {
62 "Ident client is configured but no ident server available on " + host
+ " (port " + port
+ ")");
64 } catch (Exception e
) {
65 throw new RuntimeException("Cannot read from ident server on " + host
+ " (port " + port
+ ")", e
);
67 StringTokenizer st
= new StringTokenizer(answer
, " :\n");
68 String username
= null;
69 while (st
.hasMoreTokens())
70 username
= st
.nextToken();
72 if (username
.equals(NO_USER
))
75 if (identPassphrase
!= null && username
.startsWith("[")) {
76 String encrypted
= username
.substring(1, username
.length() - 1);
77 username
= openSslDecryptor
.decryptAuthd(encrypted
, identPassphrase
).trim();
79 // System.out.println(username);
83 public void setOpenSslDecryptor(OpenSslDecryptor openSslDecryptor
) {
84 this.openSslDecryptor
= openSslDecryptor
;
87 public static String
readPassphrase(String filePath
) {
88 return readPassphrase(Paths
.get(filePath
));
91 /** @return the first line of the file. */
92 public static String
readPassphrase(Path path
) {
93 if (!isPathAvailable(path
))
97 lines
= Files
.readAllLines(path
);
98 } catch (IOException e
) {
99 throw new IllegalStateException("Cannot read " + path
, e
);
101 if (lines
.size() == 0)
103 String passphrase
= lines
.get(0);
107 public static boolean isDefaultAuthdPassphraseFileAvailable() {
108 return isPathAvailable(Paths
.get(AUTHD_PASSPHRASE_PATH
));
111 public static boolean isPathAvailable(Path path
) {
112 if (!Files
.exists(path
))
114 if (!Files
.isReadable(path
))
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
);