2025-12-12 21:16:13 +01:00
|
|
|
package org.openautonomousconnection.webserver.api;
|
|
|
|
|
|
2026-02-01 19:28:45 +01:00
|
|
|
import org.openautonomousconnection.protocol.side.server.CustomConnectedClient;
|
2025-12-12 21:16:13 +01:00
|
|
|
import org.openautonomousconnection.protocol.side.web.ProtocolWebServer;
|
|
|
|
|
import org.openautonomousconnection.protocol.side.web.managers.SessionManager;
|
|
|
|
|
|
|
|
|
|
import java.io.IOException;
|
2026-02-11 23:20:06 +01:00
|
|
|
import java.util.Locale;
|
2025-12-12 21:16:13 +01:00
|
|
|
import java.util.Map;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Provides session-related information for Java WebPages.
|
2026-02-11 23:20:06 +01:00
|
|
|
* Reads session id primarily from Cookie header ("session=...").
|
2025-12-12 21:16:13 +01:00
|
|
|
*/
|
|
|
|
|
public final class SessionContext {
|
|
|
|
|
|
2026-02-11 23:20:06 +01:00
|
|
|
private static final String COOKIE_NAME = "session";
|
|
|
|
|
|
2025-12-12 21:16:13 +01:00
|
|
|
private final String sessionId;
|
|
|
|
|
private final String user;
|
|
|
|
|
private final boolean valid;
|
|
|
|
|
|
|
|
|
|
private SessionContext(String sessionId, String user, boolean valid) {
|
|
|
|
|
this.sessionId = sessionId;
|
|
|
|
|
this.user = user;
|
|
|
|
|
this.valid = valid;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-11 23:20:06 +01:00
|
|
|
/**
|
|
|
|
|
* Creates a SessionContext from request headers (case-insensitive).
|
|
|
|
|
*
|
|
|
|
|
* @param client connected client
|
|
|
|
|
* @param server web server
|
|
|
|
|
* @param headers request headers
|
|
|
|
|
* @return session context
|
|
|
|
|
* @throws IOException on errors
|
|
|
|
|
*/
|
2026-02-01 19:28:45 +01:00
|
|
|
public static SessionContext from(CustomConnectedClient client, ProtocolWebServer server, Map<String, String> headers) throws IOException {
|
2026-02-11 23:20:06 +01:00
|
|
|
if (headers == null || headers.isEmpty()) return new SessionContext(null, null, false);
|
2025-12-12 21:16:13 +01:00
|
|
|
|
2026-02-11 23:20:06 +01:00
|
|
|
String sessionId = extractSessionId(headers);
|
|
|
|
|
if (sessionId == null || sessionId.isBlank()) return new SessionContext(null, null, false);
|
2025-12-12 21:16:13 +01:00
|
|
|
|
2026-02-11 23:20:06 +01:00
|
|
|
String ip = (client != null
|
|
|
|
|
&& client.getConnection() != null
|
|
|
|
|
&& client.getConnection().getTcpSocket() != null
|
|
|
|
|
&& client.getConnection().getTcpSocket().getInetAddress() != null)
|
|
|
|
|
? client.getConnection().getTcpSocket().getInetAddress().getHostAddress()
|
|
|
|
|
: "";
|
2025-12-12 21:16:13 +01:00
|
|
|
|
2026-02-11 23:20:06 +01:00
|
|
|
String userAgent = getHeaderIgnoreCase(headers, "user-agent");
|
|
|
|
|
if (userAgent == null) userAgent = "";
|
2025-12-12 21:16:13 +01:00
|
|
|
|
|
|
|
|
boolean valid = SessionManager.isValid(sessionId, ip, userAgent, server);
|
|
|
|
|
if (!valid) return new SessionContext(sessionId, null, false);
|
|
|
|
|
|
|
|
|
|
String user = SessionManager.getUser(sessionId);
|
|
|
|
|
return new SessionContext(sessionId, user, true);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-11 23:20:06 +01:00
|
|
|
private static String extractSessionId(Map<String, String> headers) {
|
|
|
|
|
// 1) Cookie header preferred
|
|
|
|
|
String cookie = getHeaderIgnoreCase(headers, "cookie");
|
|
|
|
|
String fromCookie = parseCookie(cookie, COOKIE_NAME);
|
|
|
|
|
if (fromCookie != null && !fromCookie.isBlank()) return fromCookie;
|
|
|
|
|
|
|
|
|
|
// 2) Backward-compatible fallback: old custom header
|
|
|
|
|
String legacy = getHeaderIgnoreCase(headers, "session");
|
|
|
|
|
return (legacy == null || legacy.isBlank()) ? null : legacy.trim();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static String parseCookie(String cookieHeader, String name) {
|
|
|
|
|
if (cookieHeader == null || cookieHeader.isBlank() || name == null || name.isBlank()) return null;
|
|
|
|
|
|
|
|
|
|
String[] parts = cookieHeader.split(";");
|
|
|
|
|
for (String p : parts) {
|
|
|
|
|
String t = p.trim();
|
|
|
|
|
int eq = t.indexOf('=');
|
|
|
|
|
if (eq <= 0) continue;
|
|
|
|
|
|
|
|
|
|
String k = t.substring(0, eq).trim();
|
|
|
|
|
if (!k.equalsIgnoreCase(name)) continue;
|
|
|
|
|
|
|
|
|
|
String v = t.substring(eq + 1).trim();
|
|
|
|
|
return v.isEmpty() ? null : v;
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static String getHeaderIgnoreCase(Map<String, String> headers, String key) {
|
|
|
|
|
if (key == null) return null;
|
|
|
|
|
String needle = key.trim().toLowerCase(Locale.ROOT);
|
|
|
|
|
for (Map.Entry<String, String> e : headers.entrySet()) {
|
|
|
|
|
if (e.getKey() == null) continue;
|
|
|
|
|
if (e.getKey().trim().toLowerCase(Locale.ROOT).equals(needle)) {
|
|
|
|
|
return e.getValue();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return whether session is valid
|
|
|
|
|
*/
|
2026-02-06 18:03:32 +01:00
|
|
|
public boolean isValid() {
|
|
|
|
|
return valid;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-11 23:20:06 +01:00
|
|
|
/**
|
|
|
|
|
* @return session id
|
|
|
|
|
*/
|
2026-02-06 18:03:32 +01:00
|
|
|
public String getSessionId() {
|
|
|
|
|
return sessionId;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-11 23:20:06 +01:00
|
|
|
/**
|
|
|
|
|
* @return user id stored in session (string)
|
|
|
|
|
*/
|
2026-02-06 18:03:32 +01:00
|
|
|
public String getUser() {
|
|
|
|
|
return user;
|
|
|
|
|
}
|
2026-02-11 23:20:06 +01:00
|
|
|
}
|