From c6858e50907b452e2c752c1d97243a141c8de51d Mon Sep 17 00:00:00 2001 From: wannes Date: Tue, 26 May 2015 23:28:22 +0200 Subject: [PATCH 01/13] Parse Ip version only when needed --- src/main/java/be/neutrinet/ispng/vpn/api/AddressLease.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/be/neutrinet/ispng/vpn/api/AddressLease.java b/src/main/java/be/neutrinet/ispng/vpn/api/AddressLease.java index 5c5fa6e..da6d44c 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/api/AddressLease.java +++ b/src/main/java/be/neutrinet/ispng/vpn/api/AddressLease.java @@ -107,10 +107,9 @@ public class AddressLease extends ResourceBase { @Delete public Representation deleteLease(Map data) { - int ipVersion = Integer.parseInt(data.get("version")); - try { if (data.containsKey("user")) { + int ipVersion = Integer.parseInt(data.get("version")); List addrs = IPAddresses.forClient(Clients.dao.queryForId(data.get("client")), ipVersion); for (IPAddress addr : addrs) { addr.client = Clients.NONE; -- GitLab From 4cfdc2871e89f8e36fbfde03564dd4b10164f2ee Mon Sep 17 00:00:00 2001 From: wannes Date: Mon, 1 Jun 2015 21:53:09 +0200 Subject: [PATCH 02/13] Initial LDAP support commit, moved users to LDAP backend and implemented DAO helpers --- src/main/java/be/neutrinet/ispng/VPN.java | 2 + .../ispng/openvpn/DefaultServiceListener.java | 49 +++---- .../be/neutrinet/ispng/security/Policy.java | 5 +- .../java/be/neutrinet/ispng/vpn/Client.java | 21 ++- .../be/neutrinet/ispng/vpn/IPAddresses.java | 11 +- .../java/be/neutrinet/ispng/vpn/User.java | 48 +++---- .../java/be/neutrinet/ispng/vpn/Users.java | 130 ++++++++++++++---- .../ispng/vpn/admin/Registration.java | 11 +- .../neutrinet/ispng/vpn/api/AddressLease.java | 2 +- .../neutrinet/ispng/vpn/api/FlowServlet.java | 6 +- .../ispng/vpn/api/UserManagement.java | 30 ++-- .../ispng/vpn/api/UserPermissions.java | 21 +-- .../ispng/vpn/api/UserRegistration.java | 4 +- .../neutrinet/ispng/vpn/api/UserSettings.java | 20 +-- .../be/neutrinet/ispng/vpn/api/VPNClient.java | 2 +- .../ispng/vpn/api/VPNClientConfig.java | 8 +- 16 files changed, 209 insertions(+), 161 deletions(-) diff --git a/src/main/java/be/neutrinet/ispng/VPN.java b/src/main/java/be/neutrinet/ispng/VPN.java index c2da3f4..39a9cbc 100644 --- a/src/main/java/be/neutrinet/ispng/VPN.java +++ b/src/main/java/be/neutrinet/ispng/VPN.java @@ -19,6 +19,7 @@ package be.neutrinet.ispng; import be.fedict.eid.applet.service.AppletServiceServlet; import be.neutrinet.ispng.config.Config; +import be.neutrinet.ispng.external.LDAP; import be.neutrinet.ispng.mail.Generator; import be.neutrinet.ispng.monitoring.Agent; import be.neutrinet.ispng.util.MariaDBType; @@ -91,6 +92,7 @@ public class VPN implements Daemon { Zookeeper.boot(cfg.getProperty("zookeeper.connectionString")); Config.get().boot(cfg); + LDAP.get().boot(); generator = new Generator(); Optional sentryApiKey = Config.get("sentry/api/dsn"); diff --git a/src/main/java/be/neutrinet/ispng/openvpn/DefaultServiceListener.java b/src/main/java/be/neutrinet/ispng/openvpn/DefaultServiceListener.java index 1c6359c..743a133 100644 --- a/src/main/java/be/neutrinet/ispng/openvpn/DefaultServiceListener.java +++ b/src/main/java/be/neutrinet/ispng/openvpn/DefaultServiceListener.java @@ -2,7 +2,6 @@ package be.neutrinet.ispng.openvpn; import be.neutrinet.ispng.VPN; import be.neutrinet.ispng.config.Config; -import be.neutrinet.ispng.monitoring.DataPoint; import be.neutrinet.ispng.vpn.*; import be.neutrinet.ispng.vpn.ip.SubnetLease; import com.google.common.collect.LinkedListMultimap; @@ -26,9 +25,11 @@ public class DefaultServiceListener implements ServiceListener { protected ManagementInterface vpn; protected boolean acceptNewConnections, acceptConnections; protected HashMap pendingConnections; + protected Monitoring monitoringAgent; public DefaultServiceListener() { pendingConnections = new HashMap<>(); + monitoringAgent = new Monitoring(); Config.get().getAndWatch("OpenVPN/connections/accept", YES, value -> acceptConnections = YES.equals(value)); Config.get().getAndWatch("OpenVPN/connections/acceptNew", YES, value -> acceptNewConnections = YES.equals(value)); @@ -43,7 +44,10 @@ public class DefaultServiceListener implements ServiceListener { be.neutrinet.ispng.vpn.Client userClient = be.neutrinet.ispng.vpn.Client.match(client).orElseGet(() -> be.neutrinet.ispng.vpn.Client.create(client)); - if (!userClient.enabled) vpn.denyClient(client.id, client.kid, "Client is disabled"); + if (!userClient.enabled) { + vpn.denyClient(client.id, client.kid, "Client is disabled"); + return; + } try { User user = Users.authenticate(client.username, client.password); @@ -55,10 +59,10 @@ public class DefaultServiceListener implements ServiceListener { else ipv4 = userClient.leases.stream().filter(addr -> addr.ipVersion == 4).findFirst(); - if (!ipv4.isPresent() && userClient.subnetLeases.isEmpty()) { + /*if (!ipv4.isPresent() && userClient.subnetLeases.isEmpty()) { vpn.denyClient(client.id, client.kid, "No IP address or subnet leases assigned"); return null; - } + }*/ Connection c = new Connection(userClient); c.openvpnInstance = vpn.getInstanceId(); @@ -98,6 +102,18 @@ public class DefaultServiceListener implements ServiceListener { // Why /64? See https://community.openvpn.net/openvpn/ticket/264 options.put("ifconfig-ipv6-push", interconnect.address + "/64" + " " + VPN.cfg.getProperty("vpn.ipv6.interconnect")); + if (!ipv4.isPresent()) { + /* because OpenVPN does not acknowledge that IPv6-only connectivity is a thing now, we need + to assign an ephemeral IPv4 address. + */ + + } + + if (user.settings().get("ip.route.ipv6.defaultRoute", true).equals(true)) { + //options.put("push redirect-gateway-ipv6", "def1"); + options.put("push route-ipv6", "2000::/3"); + } + if (!userClient.subnetLeases.isEmpty()) { for (SubnetLease lease : userClient.subnetLeases) { options.put("push route-ipv6", VPN.cfg.getProperty("vpn.ipv6.network") + "/" + VPN.cfg.getProperty("vpn.ipv6.prefix") @@ -106,11 +122,6 @@ public class DefaultServiceListener implements ServiceListener { options.put("iroute-ipv6", lease.subnet.subnet); options.put("setenv-safe DELEGATED_IPv6_PREFIX", lease.subnet.subnet); } - - if (user.settings().get("ip.route.ipv6.defaultRoute").isPresent()) { - //options.put("push redirect-gateway-ipv6", "def1"); - options.put("push route-ipv6", "2000::/3"); - } } if (VPN.cfg.containsKey("openvpn.ping")) { @@ -228,25 +239,7 @@ public class DefaultServiceListener implements ServiceListener { @Override public void bytecount(Client client, long bytesIn, long bytesOut) { - HashMap tags = new HashMap<>(); - tags.put("client", "" + client.id); - tags.put("connection", "" + client.kid); - tags.put("vpnInstance", "" + vpn.getInstanceId().replace(':', '-')); - - DataPoint bytesInDataPoint = new DataPoint(); - bytesInDataPoint.metric = "vpn.client.bytesIn"; - bytesInDataPoint.timestamp = System.currentTimeMillis(); - bytesInDataPoint.value = bytesIn; - bytesInDataPoint.tags = tags; - - DataPoint bytesOutDataPoint = new DataPoint(); - bytesOutDataPoint.metric = "vpn.client.bytesOut"; - bytesOutDataPoint.timestamp = System.currentTimeMillis(); - bytesOutDataPoint.value = bytesOut; - bytesOutDataPoint.tags = tags; - - VPN.monitoringAgent.addDataPoint(bytesInDataPoint); - VPN.monitoringAgent.addDataPoint(bytesOutDataPoint); + monitoringAgent.byteCount(client, bytesIn, bytesOut, vpn.getInstanceId().replace(':', '-')); } @Override diff --git a/src/main/java/be/neutrinet/ispng/security/Policy.java b/src/main/java/be/neutrinet/ispng/security/Policy.java index 249fa4a..a6d6356 100644 --- a/src/main/java/be/neutrinet/ispng/security/Policy.java +++ b/src/main/java/be/neutrinet/ispng/security/Policy.java @@ -5,6 +5,7 @@ import be.neutrinet.ispng.vpn.User; import java.util.ArrayList; import java.util.List; +import java.util.UUID; import java.util.stream.Collectors; /** @@ -51,7 +52,7 @@ public class Policy { boolean match = false; String[] str = VPN.cfg.getProperty("users.admin").split(";"); for (String s : str) { - if (user.id == Integer.parseInt(s)) { + if (user.globalId.equals(UUID.fromString(s))) { match = true; } } @@ -65,7 +66,7 @@ public class Policy { boolean match = false; String[] str = VPN.cfg.getProperty("users.service").split(";"); for (String s : str) { - if (user.id == Integer.parseInt(s)) { + if (user.globalId.equals(UUID.fromString(s))) { match = true; } } diff --git a/src/main/java/be/neutrinet/ispng/vpn/Client.java b/src/main/java/be/neutrinet/ispng/vpn/Client.java index 031597f..566324a 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/Client.java +++ b/src/main/java/be/neutrinet/ispng/vpn/Client.java @@ -14,6 +14,7 @@ import java.sql.SQLException; import java.util.HashMap; import java.util.List; import java.util.Optional; +import java.util.UUID; /** * Created by wannes on 11/10/14. @@ -25,8 +26,8 @@ public class Client implements OwnedEntity, Serializable { public int id; @DatabaseField(canBeNull = false) public String commonName; - @DatabaseField(canBeNull = false, foreign = true, foreignAutoRefresh = true) - public User user; + @DatabaseField(canBeNull = false) + public UUID userId; @ForeignCollectionField(foreignColumnName = "client") @JsonManagedReference public ForeignCollection leases; @@ -35,16 +36,17 @@ public class Client implements OwnedEntity, Serializable { public ForeignCollection subnetLeases; @DatabaseField(defaultValue = "true") public boolean enabled; + private User user; public static Optional match(be.neutrinet.ispng.openvpn.Client vpnClient) { try { - List users = Users.dao.queryForEq("email", vpnClient.username); + List users = Users.query("email", vpnClient.username); assert users.size() == 1; User user = users.get(0); HashMap query = new HashMap<>(); - query.put("user_id", user.id); + query.put("user_id", user.globalId); query.put("commonName", vpnClient.commonName); List clients = Clients.dao.queryForFieldValues(query); @@ -68,12 +70,12 @@ public class Client implements OwnedEntity, Serializable { c.commonName = client.commonName; try { - List users = Users.dao.queryForEq("email", client.username); + List users = Users.query("email", client.username); assert users.size() == 1; User user = users.get(0); - c.user = user; + c.userId = user.globalId; c.enabled = true; Clients.dao.createIfNotExists(c); @@ -102,8 +104,13 @@ public class Client implements OwnedEntity, Serializable { return interconnect; } + public User user() { + if (user == null) Users.queryForId(userId); + return user; + } + @Override public boolean isOwnedBy(User user) { - return this.user.equals(user); + return this.userId.equals(user.globalId); } } diff --git a/src/main/java/be/neutrinet/ispng/vpn/IPAddresses.java b/src/main/java/be/neutrinet/ispng/vpn/IPAddresses.java index af4dc9a..adb0622 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/IPAddresses.java +++ b/src/main/java/be/neutrinet/ispng/vpn/IPAddresses.java @@ -29,10 +29,7 @@ import com.tufar.IPCalculator.IPv4; import org.apache.log4j.Logger; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Optional; +import java.util.*; /** * @author wannes @@ -77,10 +74,10 @@ public class IPAddresses { return Optional.empty(); } - public static List forUser(User user, int ipVersion) { + public static List forUser(UUID userId, int ipVersion) { try { ArrayList addrs = new ArrayList<>(); - List clients = Clients.dao.queryForEq("user_id", "" + user.id); + List clients = Clients.dao.queryForEq("user_id", "" + userId); for (Client client : clients) { addrs.addAll(client.leases); } @@ -107,7 +104,7 @@ public class IPAddresses { } catch (SQLException ex) { Logger.getLogger(IPAddresses.class).error("Failed to find IP address", ex); } - return null; + return new ArrayList<>(); } public static List addv4SubnetToPool(String subnetCIDR, String purpose) { diff --git a/src/main/java/be/neutrinet/ispng/vpn/User.java b/src/main/java/be/neutrinet/ispng/vpn/User.java index 6be577c..8180c36 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/User.java +++ b/src/main/java/be/neutrinet/ispng/vpn/User.java @@ -18,8 +18,9 @@ package be.neutrinet.ispng.vpn; import be.neutrinet.ispng.security.OwnedEntity; -import com.j256.ormlite.field.DatabaseField; -import com.j256.ormlite.table.DatabaseTable; +import com.unboundid.ldap.sdk.persist.LDAPField; +import com.unboundid.ldap.sdk.persist.LDAPGetter; +import com.unboundid.ldap.sdk.persist.LDAPObject; import org.mindrot.jbcrypt.BCrypt; import java.util.Calendar; @@ -30,38 +31,36 @@ import java.util.UUID; * * @author wannes */ -@DatabaseTable(tableName = "users") +@LDAPObject(requestAllAttributes = true, structuralClass = "inetOrgPerson", auxiliaryClass = {"ispngAccount", "extensibleObject"}) public class User implements OwnedEntity { // Currently allowed countries = benelux public transient final String[] ALLOWED_COUNTRIES = new String[]{"BELGIUM", "NETHERLANDS", "LUXEMBOURG"}; - @DatabaseField(generatedId = true) - public int id; - @DatabaseField(canBeNull = false) + @LDAPField(attribute = "uid", objectClass = "inetOrgPerson", requiredForEncode = true) public UUID globalId; - @DatabaseField(canBeNull = false, index = true, unique = true) + @LDAPField(attribute = "mail", inRDN = true, requiredForEncode = true) public String email; - @DatabaseField(canBeNull = false) + @LDAPField(attribute = "gn", objectClass = "inetOrgPerson", requiredForEncode = true) public String name; - @DatabaseField(canBeNull = false) + @LDAPField(attribute = "sn", objectClass = "inetOrgPerson", requiredForEncode = true) public String lastName; - @DatabaseField + @LDAPField(objectClass = "inetOrgPerson") public String street; - @DatabaseField + @LDAPField(objectClass = "inetOrgPerson") public String postalCode; - @DatabaseField + @LDAPField(attribute = "l", requiredForEncode = true) public String municipality; - @DatabaseField(canBeNull = false) + @LDAPField(objectClass = "ispngAccount") public String birthPlace; - @DatabaseField(canBeNull = false) + @LDAPField(objectClass = "ispngAccount") public Date birthDate; - @DatabaseField + @LDAPField(objectClass = "ispngAccount") public boolean enabled; - @DatabaseField + @LDAPField(attribute = "PKCScertificateIdentifier", objectClass = "ispngAccount") public String certId; - @DatabaseField + @LDAPField(attribute = "countryName", objectClass = "extensibleObject") public String country; - @DatabaseField(canBeNull = false) + @LDAPField(attribute = "userPassword", requiredForEncode = true) private String password; private transient UserSettings settings; @@ -69,8 +68,9 @@ public class User implements OwnedEntity { this.globalId = UUID.randomUUID(); } - public boolean validatePassword(String password) { - return BCrypt.checkpw(password, this.password); + @LDAPGetter(attribute = "cn") + public String getCN() { + return email; } public String getPassword() { @@ -113,7 +113,7 @@ public class User implements OwnedEntity { public UserSettings settings() { if (settings == null) { - settings = new UserSettings("" + id); + settings = new UserSettings("" + globalId); settings.load(); } @@ -123,7 +123,7 @@ public class User implements OwnedEntity { @Override public boolean isOwnedBy(User user) { if (user == null) return false; - return user.id == id; + return user.globalId == globalId; } @Override @@ -133,13 +133,13 @@ public class User implements OwnedEntity { User user = (User) o; - if (id != user.id) return false; + if (!globalId.equals(user.globalId)) return false; return true; } @Override public int hashCode() { - return id; + return globalId.hashCode(); } } diff --git a/src/main/java/be/neutrinet/ispng/vpn/Users.java b/src/main/java/be/neutrinet/ispng/vpn/Users.java index 1a61eea..9c9a50d 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/Users.java +++ b/src/main/java/be/neutrinet/ispng/vpn/Users.java @@ -17,14 +17,19 @@ */ package be.neutrinet.ispng.vpn; -import be.neutrinet.ispng.VPN; -import com.j256.ormlite.dao.Dao; -import com.j256.ormlite.dao.DaoManager; -import com.j256.ormlite.table.TableUtils; +import be.neutrinet.ispng.config.Config; +import be.neutrinet.ispng.external.LDAP; +import com.unboundid.ldap.sdk.*; +import com.unboundid.ldap.sdk.persist.LDAPPersistException; +import com.unboundid.ldap.sdk.persist.LDAPPersister; +import com.unboundid.ldap.sdk.persist.ObjectSearchListener; +import com.unboundid.ldap.sdk.persist.PersistedObjects; import org.apache.log4j.Logger; -import java.sql.SQLException; +import java.util.ArrayList; import java.util.List; +import java.util.Optional; +import java.util.UUID; /** * @@ -32,39 +37,118 @@ import java.util.List; */ public class Users { - public static Dao dao; + public static LDAPPersister persister; public static User NOBODY; public final static User authenticate(String email, String password) { try { - List users = dao.queryForEq("email", email); - if (users.isEmpty()) { - return null; - } - if (users.size() > 1) { - throw new IllegalStateException("User " + email + " has multiple entries!"); - } - User user = users.get(0); - if (user.enabled && user.validatePassword(password)) { - return user; - } - } catch (SQLException ex) { + SearchRequest searchRequest = new SearchRequest("", SearchScope.SUB, email); + + } catch (LDAPException ex) { Logger.getLogger(Users.class).error("Failed to authenticate", ex); } return null; } + public static void add(User user) { + try { + persister.add(user, LDAP.connection(), usersDN()); + } catch (LDAPException ex) { + Logger.getLogger(Users.class).error("Failed to add user", ex); + } + } + + public static List query(String field, Object value) { + ArrayList users = new ArrayList<>(); + try { + PersistedObjects objects = persister.search(LDAP.connection(), + usersDN(), + SearchScope.SUB, + DereferencePolicy.ALWAYS, + Integer.MAX_VALUE, + 0, + Filter.create("(" + LDAP.findAttributeName(User.class, field) + "=" + value + ")")); + + User user = objects.next(); + while (user != null) { + users.add(user); + user = objects.next(); + } + + objects.close(); + + } catch (LDAPException ex) { + Logger.getLogger(Users.class).error("Failed to query LDAP for user(s)", ex); + } + + return users; + } + + public static User queryForId(String id) { + List users = query("uid", id); + assert users.size() <= 1; + if (users.size() == 1) return users.get(0); + else return null; + } + + public static User queryForId(UUID id) { + assert id != null; + return queryForId(id.toString()); + } + + public static List queryForAll() { + ArrayList users = new ArrayList<>(); + try { + persister.getAll(LDAP.connection(), usersDN(), new ObjectSearchListener() { + @Override + public void objectReturned(User user) { + users.add(user); + } + + @Override + public void unparsableEntryReturned(SearchResultEntry searchResultEntry, LDAPPersistException e) { + + } + + @Override + public void searchReferenceReturned(SearchResultReference searchResultReference) { + + } + }); + } catch (LDAPException ex) { + Logger.getLogger(Users.class).error("Failed to list all users", ex); + } + + return users; + } + + public static User update(User user) { + try { + persister.modify(user, LDAP.connection(), usersDN(), true); + } catch (LDAPException ex) { + Logger.getLogger(Users.class).error("Failed to update user " + user.email, ex); + } + + return user; + } + + protected static String usersDN() { + Optional dn = Config.get().getValue("ldap/users/dn"); + if (!dn.isPresent()) { + throw new IllegalArgumentException("No LDAP users DN set"); + } else return dn.get(); + } + static { Class cls = User.class; try { - dao = DaoManager.createDao(VPN.cs, cls); - TableUtils.createTableIfNotExists(VPN.cs, cls); - } catch (SQLException ex) { - org.apache.log4j.Logger.getLogger(cls).error("Failed to create DAO", ex); + persister = LDAPPersister.getInstance(cls); + } catch (LDAPPersistException ex) { + org.apache.log4j.Logger.getLogger(cls).error("Failed to create LDAP persister", ex); } NOBODY = new User(); - NOBODY.id = -1; + NOBODY.globalId = UUID.fromString("00000000-0000-0000-0000-000000000000"); } } diff --git a/src/main/java/be/neutrinet/ispng/vpn/admin/Registration.java b/src/main/java/be/neutrinet/ispng/vpn/admin/Registration.java index 6a67a69..45714bd 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/admin/Registration.java +++ b/src/main/java/be/neutrinet/ispng/vpn/admin/Registration.java @@ -6,8 +6,6 @@ package be.neutrinet.ispng.vpn.admin; import be.neutrinet.ispng.VPN; -import be.neutrinet.ispng.external.billy.ChangeList; -import be.neutrinet.ispng.federation.Dispatcher; import be.neutrinet.ispng.util.DateUtil; import be.neutrinet.ispng.vpn.*; import be.neutrinet.ispng.vpn.api.VPNClientCertificate; @@ -70,7 +68,7 @@ public class Registration { try { this.client = new Client(); this.client.commonName = "!!TEMPORARY_CN!!"; - this.client.user = this.user; + this.client.userId = this.user.globalId; this.client.enabled = true; Clients.dao.create(client); @@ -100,17 +98,14 @@ public class Registration { } this.completed = new Date(); - this.client.user.enabled = true; - Users.dao.update(this.client.user); + this.client.user().enabled = true; + Users.update(this.client.user()); // Check if user has certificates that need to be signed Certificates.dao.queryForEq("client_id", client.id).forEach(VPNClientCertificate::sign); Registrations.dao.update(this); - // Inform other services that a user change occurred - Dispatcher.get().entityChange(new ChangeList("user").put(ChangeList.Operation.CREATE, this.client.user.globalId.toString())); - if (sendConfirmationEmail) VPN.generator.sendRegistrationConfirmation(this); return true; }); diff --git a/src/main/java/be/neutrinet/ispng/vpn/api/AddressLease.java b/src/main/java/be/neutrinet/ispng/vpn/api/AddressLease.java index e86f4eb..5e19090 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/api/AddressLease.java +++ b/src/main/java/be/neutrinet/ispng/vpn/api/AddressLease.java @@ -63,7 +63,7 @@ public class AddressLease extends ResourceBase { try { Client client = Clients.dao.queryForId("" + clientId); - List addresses = IPAddresses.forUser(client.user, version); + List addresses = IPAddresses.forUser(client.userId, version); if (addresses.size() > 1) return clientError("MAX_IP_ADDRESSES_EXCEEDED", Status.CLIENT_ERROR_NOT_ACCEPTABLE); diff --git a/src/main/java/be/neutrinet/ispng/vpn/api/FlowServlet.java b/src/main/java/be/neutrinet/ispng/vpn/api/FlowServlet.java index 9721afb..d56e29a 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/api/FlowServlet.java +++ b/src/main/java/be/neutrinet/ispng/vpn/api/FlowServlet.java @@ -64,7 +64,7 @@ public class FlowServlet extends HttpServlet { user.municipality = address.getMunicipality(); user.certId = identity.chipNumber; - Users.dao.create(user); + Users.add(user); reg.createInitialClient(); Registrations.dao.update(reg); @@ -78,8 +78,8 @@ public class FlowServlet extends HttpServlet { case "confirm-email": try { Registration r = Registrations.dao.queryForEq("id", id).get(0); - r.client.user.enabled = true; - Users.dao.update(r.client.user); + r.client.user().enabled = true; + Users.update(r.client.user()); resp.sendRedirect("/?id=" + id + "&flow=emailDone"); } catch (SQLException ex) { diff --git a/src/main/java/be/neutrinet/ispng/vpn/api/UserManagement.java b/src/main/java/be/neutrinet/ispng/vpn/api/UserManagement.java index 386d7ab..f1c6a0e 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/api/UserManagement.java +++ b/src/main/java/be/neutrinet/ispng/vpn/api/UserManagement.java @@ -6,7 +6,6 @@ package be.neutrinet.ispng.vpn.api; import be.neutrinet.ispng.security.Policy; -import be.neutrinet.ispng.util.UUIDUtil; import be.neutrinet.ispng.vpn.User; import be.neutrinet.ispng.vpn.Users; import org.apache.log4j.Logger; @@ -34,15 +33,15 @@ public class UserManagement extends ResourceBase { try { if (!getRequestAttributes().containsKey("user") || getAttribute("user").equals("all")) { - List users = Users.dao.queryForAll(); + List users = Users.queryForAll(); return new JacksonRepresentation(Policy.filterAccessible(getSessionToken().get().getUser(), users)); } String id = getAttribute("user"); - if (UUIDUtil.isUUID(id)) { + User user; - List users = Users.dao.queryForEq("globalId", UUID.fromString(id)); + List users = Users.query("globalId", UUID.fromString(id)); if (users.isEmpty()) { return clientError("NO_SUCH_OBJECT", Status.SUCCESS_NO_CONTENT); } else { @@ -54,20 +53,7 @@ public class UserManagement extends ResourceBase { } else { return clientError("FORBIDDEN", Status.CLIENT_ERROR_BAD_REQUEST); } - } else { - int userId = Integer.parseInt(getAttribute("user")); - if (!Users.dao.idExists("" + userId)) { - return clientError("NO_SUCH_OBJECT", Status.SUCCESS_NO_CONTENT); - } - - User user = Users.dao.queryForId("" + userId); - if (Policy.get().canAccess(getSessionToken().get().getUser(), user)) { - return new JacksonRepresentation(user); - } else { - return clientError("FORBIDDEN", Status.CLIENT_ERROR_BAD_REQUEST); - } - } } catch (Exception ex) { Logger.getLogger(getClass()).error("Failed to retrieve users", ex); } @@ -83,13 +69,13 @@ public class UserManagement extends ResourceBase { getAttribute("user").equals("all")) { return clientError("MALFORMED_REQUEST", Status.CLIENT_ERROR_BAD_REQUEST); } - int userId = Integer.parseInt(getAttribute("user")); - if (userId != user.id) { + UUID userId = UUID.fromString(getAttribute("user")); + if (!userId.equals(user.globalId)) { return clientError("MALFORMED_REQUEST", Status.CLIENT_ERROR_BAD_REQUEST); } try { - User old = Users.dao.queryForId("" + userId); + User old = Users.queryForId("" + userId); if (!Policy.get().canModify(getSessionToken().get().getUser(), old)) { return clientError("FORBIDDEN", Status.CLIENT_ERROR_BAD_REQUEST); } @@ -98,7 +84,7 @@ public class UserManagement extends ResourceBase { // Deserialized object contains plaintext new password // the setPassword is invoked by Restlet, set the hash directly (do not rehash) old.setRawPassword(user.getPassword()); - Users.dao.update(old); + Users.update(old); return new JacksonRepresentation<>(old); } @@ -107,7 +93,7 @@ public class UserManagement extends ResourceBase { Optional optional = mergeUpdate(old, user, prohibitedFields); if (optional.isPresent()) { - Users.dao.update(optional.get()); + Users.update(optional.get()); } } catch (Exception ex) { Logger.getLogger(getClass()).error("Failed to update user", ex); diff --git a/src/main/java/be/neutrinet/ispng/vpn/api/UserPermissions.java b/src/main/java/be/neutrinet/ispng/vpn/api/UserPermissions.java index 63c863d..a599990 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/api/UserPermissions.java +++ b/src/main/java/be/neutrinet/ispng/vpn/api/UserPermissions.java @@ -3,14 +3,11 @@ package be.neutrinet.ispng.vpn.api; import be.neutrinet.ispng.security.Policy; import be.neutrinet.ispng.vpn.User; import be.neutrinet.ispng.vpn.Users; -import org.apache.log4j.Logger; import org.restlet.data.Status; import org.restlet.ext.jackson.JacksonRepresentation; import org.restlet.representation.Representation; import org.restlet.resource.Get; -import java.sql.SQLException; - /** * Created by wannes on 3/21/15. */ @@ -22,19 +19,13 @@ public class UserPermissions extends ResourceBase { return clientError("INVALID_REQUEST", Status.CLIENT_ERROR_BAD_REQUEST); String id = getAttribute("user"); - try { - User user = Users.dao.queryForId(id); - if (!Policy.get().canAccess(getLoggedInUser(), user)) - return clientError("UNAUTHORIZED", Status.CLIENT_ERROR_FORBIDDEN); - - Permissions permissions = new Permissions(); - permissions.build(user); - return new JacksonRepresentation<>(permissions); - } catch (SQLException ex) { - Logger.getLogger(getClass()).error("Failed to retrieve user permissions", ex); - } + User user = Users.queryForId(id); + if (!Policy.get().canAccess(getLoggedInUser(), user)) + return clientError("UNAUTHORIZED", Status.CLIENT_ERROR_FORBIDDEN); - return DEFAULT_ERROR; + Permissions permissions = new Permissions(); + permissions.build(user); + return new JacksonRepresentation<>(permissions); } protected class Permissions { diff --git a/src/main/java/be/neutrinet/ispng/vpn/api/UserRegistration.java b/src/main/java/be/neutrinet/ispng/vpn/api/UserRegistration.java index 220ae97..dbd79c7 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/api/UserRegistration.java +++ b/src/main/java/be/neutrinet/ispng/vpn/api/UserRegistration.java @@ -60,7 +60,7 @@ public class UserRegistration extends ResourceBase { // Legacy fix if (reg.client == null) { - reg.client = Clients.dao.queryForEq("user_id", reg.user.id).get(0); + reg.client = Clients.dao.queryForEq("user_id", reg.user.globalId).get(0); } } catch (SQLException ex) { @@ -154,7 +154,7 @@ public class UserRegistration extends ResourceBase { reg.user.birthPlace = (String) data.get("birthplace"); reg.user.country = (String) data.get("country"); - if (reg.user.validate()) Users.dao.createIfNotExists(reg.user); + if (reg.user.validate()) Users.add(reg.user); // Auto-login newly created user getResponse().getCookieSettings().add("Session", diff --git a/src/main/java/be/neutrinet/ispng/vpn/api/UserSettings.java b/src/main/java/be/neutrinet/ispng/vpn/api/UserSettings.java index 582ad96..18cb494 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/api/UserSettings.java +++ b/src/main/java/be/neutrinet/ispng/vpn/api/UserSettings.java @@ -3,14 +3,12 @@ package be.neutrinet.ispng.vpn.api; import be.neutrinet.ispng.vpn.User; import be.neutrinet.ispng.vpn.Users; import net.wgr.core.StringUtils; -import org.apache.log4j.Logger; import org.restlet.data.Status; import org.restlet.ext.jackson.JacksonRepresentation; import org.restlet.resource.Delete; import org.restlet.resource.Get; import org.restlet.resource.Post; -import java.sql.SQLException; import java.util.Map; /** @@ -21,19 +19,13 @@ public class UserSettings extends ResourceBase { private User getUserFromRequest() { String userId = getRequestAttributes().get("user").toString(); - try { - User user = null; - if (!StringUtils.isNumeric(userId)) - user = Users.dao.queryForEq("email", userId).get(0); - else - user = Users.dao.queryForId(userId); + User user = null; + if (!StringUtils.isNumeric(userId)) + user = Users.query("email", userId).get(0); + else + user = Users.queryForId(userId); - return user; - } catch (SQLException e) { - Logger.getLogger(getClass()).error("Unknown user", e); - } - - return null; + return user; } @Get diff --git a/src/main/java/be/neutrinet/ispng/vpn/api/VPNClient.java b/src/main/java/be/neutrinet/ispng/vpn/api/VPNClient.java index bb97d74..241fb2d 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/api/VPNClient.java +++ b/src/main/java/be/neutrinet/ispng/vpn/api/VPNClient.java @@ -44,7 +44,7 @@ public class VPNClient extends ResourceBase { @Put public Representation addVPNClient(Client client) { if ((client.commonName == null || client.commonName.isEmpty()) || - (client.user == null)) { + (client.userId == null)) { return clientError("MALFORMED_REQUEST", Status.CLIENT_ERROR_BAD_REQUEST); } diff --git a/src/main/java/be/neutrinet/ispng/vpn/api/VPNClientConfig.java b/src/main/java/be/neutrinet/ispng/vpn/api/VPNClientConfig.java index 5547c5f..b5df8a4 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/api/VPNClientConfig.java +++ b/src/main/java/be/neutrinet/ispng/vpn/api/VPNClientConfig.java @@ -63,7 +63,7 @@ public class VPNClientConfig extends ResourceBase { String platform = getQueryValue("platform"); try { - User user = Users.dao.queryForId(userId); + User user = Users.queryForId(userId); if (user.certId == null) return clientError("NO_KEYPAIR", Status.CLIENT_ERROR_FAILED_DEPENDENCY); ArrayList config = new ArrayList<>(); @@ -116,12 +116,12 @@ public class VPNClientConfig extends ResourceBase { + " here and name it client.key").getBytes()); config.add("cert client.crt"); config.add("key client.key"); - } else if (client.user.certId != null && !client.user.certId.isEmpty()) { - Representation res = addPKCS11config(data.get("platform").toLowerCase(), config, client.user); + } else if (client.user().certId != null && !client.user().certId.isEmpty()) { + Representation res = addPKCS11config(data.get("platform").toLowerCase(), config, client.user()); if (res != null) return res; } - if (client.user.certId == null || client.user.certId.isEmpty()) { + if (client.user().certId == null || client.user().certId.isEmpty()) { zip.putNextEntry(new ZipEntry("NO_KEYPAIR_DEFINED")); zip.write("Invalid state, no keypair has been defined.".getBytes()); } -- GitLab From 163d9a489c3ccf30a7939faa9004631047acdfa4 Mon Sep 17 00:00:00 2001 From: wannes Date: Mon, 1 Jun 2015 21:56:42 +0200 Subject: [PATCH 03/13] Ideally do not forget to include the DAO helper --- .../be/neutrinet/ispng/external/LDAP.java | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 src/main/java/be/neutrinet/ispng/external/LDAP.java diff --git a/src/main/java/be/neutrinet/ispng/external/LDAP.java b/src/main/java/be/neutrinet/ispng/external/LDAP.java new file mode 100644 index 0000000..dee4a70 --- /dev/null +++ b/src/main/java/be/neutrinet/ispng/external/LDAP.java @@ -0,0 +1,105 @@ +package be.neutrinet.ispng.external; + +import be.neutrinet.ispng.config.Config; +import com.unboundid.ldap.sdk.BindRequest; +import com.unboundid.ldap.sdk.BindResult; +import com.unboundid.ldap.sdk.LDAPConnection; +import com.unboundid.ldap.sdk.SimpleBindRequest; +import com.unboundid.ldap.sdk.controls.PasswordExpiredControl; +import com.unboundid.ldap.sdk.controls.PasswordExpiringControl; +import com.unboundid.ldap.sdk.persist.LDAPField; +import com.unboundid.util.ssl.SSLUtil; +import com.unboundid.util.ssl.TrustAllTrustManager; +import org.apache.log4j.Logger; + +import javax.net.SocketFactory; +import java.lang.reflect.Field; +import java.util.Optional; + +/** + * Created by wannes on 27/05/15. + */ +public class LDAP { + private LDAPConnection connection; + private Logger logger = Logger.getLogger(getClass()); + private final static LDAP instance = new LDAP(); + + private LDAP() { + + } + + public static LDAP get() { + return instance; + } + + public void boot() { + Optional host = Config.get("ldap/host"); + if (host.isPresent()) { + try { + SSLUtil sslUtil = new SSLUtil(null, new TrustAllTrustManager()); + SocketFactory socketFactory = sslUtil.createSSLSocketFactory(); + connection = new LDAPConnection(socketFactory, host.get(), Integer.parseInt(Config.get("ldap/port", "636"))); + + Optional dn = Config.get("ldap/bind/dn"); + Optional password = Config.get("ldap/bind/password"); + + if (!dn.isPresent() || !password.isPresent()) { + throw new IllegalArgumentException("LDAP bind DN and/or password not present"); + } + + BindRequest bindRequest = new SimpleBindRequest(dn.get(), password.get()); + BindResult bindResult = connection.bind(bindRequest); + + PasswordExpiredControl pwdExpired = PasswordExpiredControl.get(bindResult); + if (pwdExpired == null) { + logger.debug("The password expired control was not included in " + + "the LDAP BIND response."); + } else { + logger.error("You must change your LDAP password " + + "before you will be allowed to perform any other operations."); + } + + PasswordExpiringControl pwdExpiring = PasswordExpiringControl.get(bindResult); + if (pwdExpiring == null) { + logger.debug("The password expiring control was not included in" + + " the LDAP BIND response."); + } else { + logger.warn("Your LDAP password will expire in " + + pwdExpiring.getSecondsUntilExpiration() + " seconds."); + } + + logger.info("Connected to LDAP"); + + } catch (Exception ex) { + logger.error("Failed to connect to LDAP server", ex); + System.exit(666); + } + } + } + + public static String findAttributeName(Class clazz, String fieldName) { + assert clazz != null; + assert fieldName != null; + + try { + for (Field f : clazz.getDeclaredFields()) { + if (f.getName().equals(fieldName)) { + LDAPField field = f.getAnnotation(LDAPField.class); + if (field != null) { + return field.attribute(); + } else { + return fieldName; + } + } + } + } catch (Exception ex) { + Logger.getLogger(LDAP.class).error("Failed to find LDAP attribute for field " + fieldName, ex); + } + + return fieldName; + } + + public static LDAPConnection connection() { + return instance.connection; + } +} -- GitLab From 0df8f2aea89f62d5b37932f8eece766abe2e9489 Mon Sep 17 00:00:00 2001 From: wannes Date: Thu, 4 Jun 2015 22:26:10 +0200 Subject: [PATCH 04/13] Fixes --- src/main/java/Bootstrap.java | 4 +-- .../be/neutrinet/ispng/dns/DNSRecord.java | 6 ++-- .../be/neutrinet/ispng/mail/Generator.java | 8 ++--- .../java/be/neutrinet/ispng/mail/Postman.java | 9 ++--- .../neutrinet/ispng/security/OwnedEntity.java | 4 +-- .../be/neutrinet/ispng/security/Policy.java | 29 ++++++---------- .../ispng/security/SessionManager.java | 2 +- .../ispng/security/SessionToken.java | 9 +++-- .../java/be/neutrinet/ispng/vpn/Client.java | 6 ++-- .../java/be/neutrinet/ispng/vpn/User.java | 14 ++++---- .../java/be/neutrinet/ispng/vpn/Users.java | 27 ++++++++++++--- .../ispng/vpn/admin/Registration.java | 17 ++++++++-- .../neutrinet/ispng/vpn/api/FlowServlet.java | 2 +- .../neutrinet/ispng/vpn/api/ResourceBase.java | 3 +- .../ispng/vpn/api/UserPermissions.java | 6 ++-- .../ispng/vpn/api/UserRegistration.java | 33 ++++++++++--------- 16 files changed, 101 insertions(+), 78 deletions(-) diff --git a/src/main/java/Bootstrap.java b/src/main/java/Bootstrap.java index 7bbda29..c7a1298 100644 --- a/src/main/java/Bootstrap.java +++ b/src/main/java/Bootstrap.java @@ -17,14 +17,14 @@ public class Bootstrap { User user = new User(); user.birthDate = new Date(); user.birthPlace = "Spaaaace!"; - user.country = "Botswana"; + user.country = "Belgium"; user.email = "boot@strap.be"; user.lastName = "Bobson"; user.name = "Alice"; user.municipality = "Moonbase A6-9K"; user.postalCode = "42"; user.setPassword("password"); - Users.dao.create(user); + Users.add(user); IPAddresses.addv4SubnetToPool("192.168.221.129/25", IPAddress.Purpose.CLIENT_ASSIGN); } diff --git a/src/main/java/be/neutrinet/ispng/dns/DNSRecord.java b/src/main/java/be/neutrinet/ispng/dns/DNSRecord.java index efbd87e..4d7757e 100644 --- a/src/main/java/be/neutrinet/ispng/dns/DNSRecord.java +++ b/src/main/java/be/neutrinet/ispng/dns/DNSRecord.java @@ -2,11 +2,11 @@ package be.neutrinet.ispng.dns; import be.neutrinet.ispng.security.OwnedEntity; import be.neutrinet.ispng.vpn.Client; -import be.neutrinet.ispng.vpn.User; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; import java.io.Serializable; +import java.util.UUID; /** * Created by wannes on 1/27/15. @@ -102,7 +102,7 @@ public class DNSRecord implements Serializable, OwnedEntity { } @Override - public boolean isOwnedBy(User user) { - return this.client.user.equals(user); + public boolean isOwnedBy(UUID user) { + return this.client.userId.equals(user); } } diff --git a/src/main/java/be/neutrinet/ispng/mail/Generator.java b/src/main/java/be/neutrinet/ispng/mail/Generator.java index cae8895..49a8a3f 100644 --- a/src/main/java/be/neutrinet/ispng/mail/Generator.java +++ b/src/main/java/be/neutrinet/ispng/mail/Generator.java @@ -42,14 +42,14 @@ public class Generator { public void sendRegistrationConfirmation(Registration r) { try { MimeMessage msg = this.postman.createNewMessage(); - msg.addRecipients(Message.RecipientType.TO, r.user.email); + msg.addRecipients(Message.RecipientType.TO, r.user().email); msg.setSubject("Registration confirmation"); HashMap content = new HashMap<>(); content.put("title", "Confirmation"); content.put("preview", "You successfully created your Neutrinet account"); - content.put("email", r.user.email); - content.put("name", r.user.name + " " + r.user.lastName); + content.put("email", r.user().email); + content.put("name", r.user().name + " " + r.user().lastName); content.put("reg-id", r.getId().toString()); if (r.ipv4Id != 0) { content.put("ipv4", IPAddresses.dao.queryForId("" + r.ipv4Id).address); @@ -92,7 +92,7 @@ public class Generator { if (c.subnetLeases != null) { for (Iterator it = c.subnetLeases.iterator(); it.hasNext(); ) { MimeMessage msg = this.postman.createNewMessage(); - msg.addRecipients(Message.RecipientType.TO, c.user.email); + msg.addRecipients(Message.RecipientType.TO, c.user().email); msg.setSubject("Your new IPv6 subnet"); HashMap content = new HashMap<>(); diff --git a/src/main/java/be/neutrinet/ispng/mail/Postman.java b/src/main/java/be/neutrinet/ispng/mail/Postman.java index f63abd7..3c55cb5 100644 --- a/src/main/java/be/neutrinet/ispng/mail/Postman.java +++ b/src/main/java/be/neutrinet/ispng/mail/Postman.java @@ -3,17 +3,18 @@ package be.neutrinet.ispng.mail; import be.neutrinet.ispng.VPN; import com.sun.mail.smtp.SMTPTransport; -import java.security.Security; -import java.util.Date; -import java.util.Properties; + import javax.mail.MessagingException; import javax.mail.Session; import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; +import java.security.Security; +import java.util.Date; +import java.util.Properties; /** - * + * TODO: find out if there are any external services with similar functionality and remove this mail piece * @author wannes */ public class Postman { diff --git a/src/main/java/be/neutrinet/ispng/security/OwnedEntity.java b/src/main/java/be/neutrinet/ispng/security/OwnedEntity.java index 4b180ea..e47fc81 100644 --- a/src/main/java/be/neutrinet/ispng/security/OwnedEntity.java +++ b/src/main/java/be/neutrinet/ispng/security/OwnedEntity.java @@ -1,10 +1,10 @@ package be.neutrinet.ispng.security; -import be.neutrinet.ispng.vpn.User; +import java.util.UUID; /** * Created by wannes on 12/20/14. */ public interface OwnedEntity { - public boolean isOwnedBy(User user); + public boolean isOwnedBy(UUID user); } diff --git a/src/main/java/be/neutrinet/ispng/security/Policy.java b/src/main/java/be/neutrinet/ispng/security/Policy.java index a6d6356..af5afeb 100644 --- a/src/main/java/be/neutrinet/ispng/security/Policy.java +++ b/src/main/java/be/neutrinet/ispng/security/Policy.java @@ -1,7 +1,6 @@ package be.neutrinet.ispng.security; import be.neutrinet.ispng.VPN; -import be.neutrinet.ispng.vpn.User; import java.util.ArrayList; import java.util.List; @@ -18,41 +17,33 @@ public class Policy { return INSTANCE; } - public static List filterAccessible(User user, List entities) { + public static List filterAccessible(UUID user, List entities) { if (entities == null) return new ArrayList<>(); return entities.parallelStream().filter(e -> INSTANCE.canAccess(user, e)).collect(Collectors.toList()); } - public static List filterModifiable(User user, List entities) { + public static List filterModifiable(UUID user, List entities) { if (entities == null) return new ArrayList<>(); return entities.parallelStream().filter(e -> INSTANCE.canModify(user, e)).collect(Collectors.toList()); } - public boolean canAccess(User user, OwnedEntity entity) { - if (entity == null || user == null) return false; - if (isAdmin(user)) return true; - if (entity.isOwnedBy(user)) return true; - - return false; + public boolean canAccess(UUID user, OwnedEntity entity) { + return !(entity == null || user == null) && (isAdmin(user) || entity.isOwnedBy(user)); } - public boolean canModify(User user, OwnedEntity entity) { - if (entity == null || user == null) return false; - if (isAdmin(user)) return true; - if (entity.isOwnedBy(user)) return true; - - return false; + public boolean canModify(UUID user, OwnedEntity entity) { + return !(entity == null || user == null) && (isAdmin(user) || entity.isOwnedBy(user)); } - public final boolean isAdmin(User user) { + public final boolean isAdmin(UUID user) { if (VPN.cfg.getProperty("users.admin") == null) return false; boolean match = false; String[] str = VPN.cfg.getProperty("users.admin").split(";"); for (String s : str) { - if (user.globalId.equals(UUID.fromString(s))) { + if (user.equals(UUID.fromString(s))) { match = true; } } @@ -60,13 +51,13 @@ public class Policy { return match; } - public final boolean isRelatedService(User user) { + public final boolean isRelatedService(UUID user) { if (VPN.cfg.getProperty("users.service") == null) return false; boolean match = false; String[] str = VPN.cfg.getProperty("users.service").split(";"); for (String s : str) { - if (user.globalId.equals(UUID.fromString(s))) { + if (user.equals(UUID.fromString(s))) { match = true; } } diff --git a/src/main/java/be/neutrinet/ispng/security/SessionManager.java b/src/main/java/be/neutrinet/ispng/security/SessionManager.java index cf571f6..92cf0e6 100644 --- a/src/main/java/be/neutrinet/ispng/security/SessionManager.java +++ b/src/main/java/be/neutrinet/ispng/security/SessionManager.java @@ -12,7 +12,7 @@ public class SessionManager { private static SessionManager instance = new SessionManager(); public static SessionToken createSessionToken(User user, String address) { - return new SessionToken(user, address); + return new SessionToken(user.globalId, address); } public static boolean validateToken(String token, String address) { diff --git a/src/main/java/be/neutrinet/ispng/security/SessionToken.java b/src/main/java/be/neutrinet/ispng/security/SessionToken.java index 45e935a..cfa7dd8 100644 --- a/src/main/java/be/neutrinet/ispng/security/SessionToken.java +++ b/src/main/java/be/neutrinet/ispng/security/SessionToken.java @@ -1,6 +1,5 @@ package be.neutrinet.ispng.security; -import be.neutrinet.ispng.vpn.User; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; import org.apache.log4j.Logger; @@ -13,8 +12,8 @@ import java.util.UUID; */ @DatabaseTable(tableName = "session_tokens") public class SessionToken { - @DatabaseField(canBeNull = false, foreign = true, foreignAutoRefresh = true) - private User user; + @DatabaseField(canBeNull = false) + private UUID user; @DatabaseField(canBeNull = false) private String address; @DatabaseField(canBeNull = false) @@ -26,7 +25,7 @@ public class SessionToken { } - public SessionToken(User user, String address) { + public SessionToken(UUID user, String address) { this.user = user; this.address = address; this.creationTime = System.currentTimeMillis(); @@ -43,7 +42,7 @@ public class SessionToken { return token; } - public User getUser() { + public UUID getUser() { return user; } diff --git a/src/main/java/be/neutrinet/ispng/vpn/Client.java b/src/main/java/be/neutrinet/ispng/vpn/Client.java index 566324a..a5559cf 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/Client.java +++ b/src/main/java/be/neutrinet/ispng/vpn/Client.java @@ -105,12 +105,12 @@ public class Client implements OwnedEntity, Serializable { } public User user() { - if (user == null) Users.queryForId(userId); + if (user == null) user = Users.queryForId(userId); return user; } @Override - public boolean isOwnedBy(User user) { - return this.userId.equals(user.globalId); + public boolean isOwnedBy(UUID user) { + return this.userId.equals(user); } } diff --git a/src/main/java/be/neutrinet/ispng/vpn/User.java b/src/main/java/be/neutrinet/ispng/vpn/User.java index 8180c36..89cd5ea 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/User.java +++ b/src/main/java/be/neutrinet/ispng/vpn/User.java @@ -40,7 +40,7 @@ public class User implements OwnedEntity { public UUID globalId; @LDAPField(attribute = "mail", inRDN = true, requiredForEncode = true) public String email; - @LDAPField(attribute = "gn", objectClass = "inetOrgPerson", requiredForEncode = true) + @LDAPField(attribute = "givenName", objectClass = "inetOrgPerson", requiredForEncode = true) public String name; @LDAPField(attribute = "sn", objectClass = "inetOrgPerson", requiredForEncode = true) public String lastName; @@ -73,6 +73,10 @@ public class User implements OwnedEntity { return email; } + public String getDN() { + return "mail=" + email + "," + Users.usersDN(); + } + public String getPassword() { return password; } @@ -121,9 +125,8 @@ public class User implements OwnedEntity { } @Override - public boolean isOwnedBy(User user) { - if (user == null) return false; - return user.globalId == globalId; + public boolean isOwnedBy(UUID user) { + return user != null && user.equals(globalId); } @Override @@ -133,9 +136,8 @@ public class User implements OwnedEntity { User user = (User) o; - if (!globalId.equals(user.globalId)) return false; + return globalId.equals(user.globalId); - return true; } @Override diff --git a/src/main/java/be/neutrinet/ispng/vpn/Users.java b/src/main/java/be/neutrinet/ispng/vpn/Users.java index 9c9a50d..603d814 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/Users.java +++ b/src/main/java/be/neutrinet/ispng/vpn/Users.java @@ -25,6 +25,7 @@ import com.unboundid.ldap.sdk.persist.LDAPPersister; import com.unboundid.ldap.sdk.persist.ObjectSearchListener; import com.unboundid.ldap.sdk.persist.PersistedObjects; import org.apache.log4j.Logger; +import org.mindrot.jbcrypt.BCrypt; import java.util.ArrayList; import java.util.List; @@ -41,11 +42,17 @@ public class Users { public static User NOBODY; public final static User authenticate(String email, String password) { - try { - SearchRequest searchRequest = new SearchRequest("", SearchScope.SUB, email); - } catch (LDAPException ex) { - Logger.getLogger(Users.class).error("Failed to authenticate", ex); + List users = query("email", email); + assert users.size() <= 1; + + if (users.size() == 1) { + User user = users.get(0); + String salt = BCrypt.gensalt(10); + String pwd = BCrypt.hashpw(password, salt); + if (user.getPassword().equals(pwd)) { + return user; + } } return null; @@ -125,7 +132,7 @@ public class Users { public static User update(User user) { try { - persister.modify(user, LDAP.connection(), usersDN(), true); + persister.modify(user, LDAP.connection(), user.getDN(), true); } catch (LDAPException ex) { Logger.getLogger(Users.class).error("Failed to update user " + user.email, ex); } @@ -133,6 +140,16 @@ public class Users { return user; } + public static User delete(User user) { + try { + persister.delete(user, LDAP.connection()); + } catch (LDAPException ex) { + Logger.getLogger(Users.class).error("Failed to delete user " + user.email, ex); + } + + return user; + } + protected static String usersDN() { Optional dn = Config.get().getValue("ldap/users/dn"); if (!dn.isPresent()) { diff --git a/src/main/java/be/neutrinet/ispng/vpn/admin/Registration.java b/src/main/java/be/neutrinet/ispng/vpn/admin/Registration.java index 45714bd..f2a5091 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/admin/Registration.java +++ b/src/main/java/be/neutrinet/ispng/vpn/admin/Registration.java @@ -29,8 +29,9 @@ import java.util.UUID; public class Registration { private static final Map activeRegistrations = new HashMap<>(); - @DatabaseField(foreign = true, foreignAutoRefresh = true) - public User user; + @DatabaseField(canBeNull = false) + public UUID user; + private User cachedUser; @DatabaseField(foreign = true, foreignAutoRefresh = true) public Client client; @DatabaseField(canBeNull = false) @@ -68,7 +69,7 @@ public class Registration { try { this.client = new Client(); this.client.commonName = "!!TEMPORARY_CN!!"; - this.client.userId = this.user.globalId; + this.client.userId = this.user; this.client.enabled = true; Clients.dao.create(client); @@ -113,4 +114,14 @@ public class Registration { Logger.getLogger(getClass()).error("Registration failed", ex); } } + + public User user() { + if (cachedUser == null) cachedUser = Users.queryForId(this.id); + return cachedUser; + } + + public void setUser(User user) { + cachedUser = user; + this.user = user.globalId; + } } diff --git a/src/main/java/be/neutrinet/ispng/vpn/api/FlowServlet.java b/src/main/java/be/neutrinet/ispng/vpn/api/FlowServlet.java index d56e29a..a02d98c 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/api/FlowServlet.java +++ b/src/main/java/be/neutrinet/ispng/vpn/api/FlowServlet.java @@ -54,7 +54,7 @@ public class FlowServlet extends HttpServlet { return; } - User user = reg.user; + User user = reg.user(); user.name = identity.getFirstName() + " " + identity.getMiddleName(); user.lastName = identity.getName(); user.birthPlace = identity.getPlaceOfBirth(); diff --git a/src/main/java/be/neutrinet/ispng/vpn/api/ResourceBase.java b/src/main/java/be/neutrinet/ispng/vpn/api/ResourceBase.java index 11b48ab..0add880 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/api/ResourceBase.java +++ b/src/main/java/be/neutrinet/ispng/vpn/api/ResourceBase.java @@ -8,7 +8,6 @@ package be.neutrinet.ispng.vpn.api; import be.neutrinet.ispng.security.SessionToken; import be.neutrinet.ispng.security.SessionTokens; import be.neutrinet.ispng.vpn.ClientError; -import be.neutrinet.ispng.vpn.User; import org.apache.log4j.Logger; import org.restlet.data.Status; import org.restlet.engine.application.CorsResponseHelper; @@ -104,7 +103,7 @@ public abstract class ResourceBase extends ServerResource { return Optional.ofNullable(token); } - public User getLoggedInUser() { + public UUID getLoggedInUser() { return getSessionToken().get().getUser(); } diff --git a/src/main/java/be/neutrinet/ispng/vpn/api/UserPermissions.java b/src/main/java/be/neutrinet/ispng/vpn/api/UserPermissions.java index a599990..fd0378e 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/api/UserPermissions.java +++ b/src/main/java/be/neutrinet/ispng/vpn/api/UserPermissions.java @@ -8,6 +8,8 @@ import org.restlet.ext.jackson.JacksonRepresentation; import org.restlet.representation.Representation; import org.restlet.resource.Get; +import java.util.UUID; + /** * Created by wannes on 3/21/15. */ @@ -24,7 +26,7 @@ public class UserPermissions extends ResourceBase { return clientError("UNAUTHORIZED", Status.CLIENT_ERROR_FORBIDDEN); Permissions permissions = new Permissions(); - permissions.build(user); + permissions.build(user.globalId); return new JacksonRepresentation<>(permissions); } @@ -32,7 +34,7 @@ public class UserPermissions extends ResourceBase { public boolean isAdmin; public boolean isService; - public void build(User user) { + public void build(UUID user) { this.isAdmin = Policy.get().isAdmin(user); this.isService = Policy.get().isRelatedService(user); } diff --git a/src/main/java/be/neutrinet/ispng/vpn/api/UserRegistration.java b/src/main/java/be/neutrinet/ispng/vpn/api/UserRegistration.java index dbd79c7..f2542bb 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/api/UserRegistration.java +++ b/src/main/java/be/neutrinet/ispng/vpn/api/UserRegistration.java @@ -60,7 +60,7 @@ public class UserRegistration extends ResourceBase { // Legacy fix if (reg.client == null) { - reg.client = Clients.dao.queryForEq("user_id", reg.user.globalId).get(0); + reg.client = Clients.dao.queryForEq("user_id", reg.user).get(0); } } catch (SQLException ex) { @@ -96,13 +96,13 @@ public class UserRegistration extends ResourceBase { Registration reg = new Registration(UUID.randomUUID()); reg.timeInitiated = new Date(); - reg.user = new User(); - reg.user.email = (String) data.get("email"); + reg.setUser(new User()); + reg.user().email = (String) data.get("email"); reg.unlockKey = unlockKey; if (data.containsKey("password")) { String password = (String) data.get("password"); - reg.user.setPassword(password); + reg.user().setPassword(password); } Registration.getActiveRegistrations().put(reg.getId(), reg); @@ -142,23 +142,24 @@ public class UserRegistration extends ResourceBase { return new JacksonRepresentation("OK"); } else if (data.containsKey("password")) { String password = (String) data.get("password"); - reg.user.setPassword(password); + reg.user().setPassword(password); return new JacksonRepresentation(reg.user); } else if (data.containsKey("name")) { - reg.user.name = (String) data.get("name"); - reg.user.lastName = (String) data.get("last-name"); - reg.user.birthDate = EUROPEAN_DATE_FORMAT.parse((String) data.get("birthdate")); - reg.user.street = (String) data.get("street"); - reg.user.municipality = (String) data.get("municipality"); - reg.user.postalCode = (String) data.get("postal-code"); - reg.user.birthPlace = (String) data.get("birthplace"); - reg.user.country = (String) data.get("country"); - - if (reg.user.validate()) Users.add(reg.user); + User user = reg.user(); + user.name = (String) data.get("name"); + user.lastName = (String) data.get("last-name"); + user.birthDate = EUROPEAN_DATE_FORMAT.parse((String) data.get("birthdate")); + user.street = (String) data.get("street"); + user.municipality = (String) data.get("municipality"); + user.postalCode = (String) data.get("postal-code"); + user.birthPlace = (String) data.get("birthplace"); + user.country = (String) data.get("country"); + + if (user.validate()) Users.add(user); // Auto-login newly created user getResponse().getCookieSettings().add("Session", - SessionManager.createSessionToken(reg.user, getClientInfo().getAddress()).getToken().toString()); + SessionManager.createSessionToken(user, getClientInfo().getAddress()).getToken().toString()); reg.createInitialClient(); Registrations.dao.update(reg); -- GitLab From 5a22d0770dc837846390e5cbe58559b2c684f517 Mon Sep 17 00:00:00 2001 From: wannes Date: Thu, 11 Jun 2015 01:12:35 +0200 Subject: [PATCH 05/13] Implement group membership checks in LDAP + refactor accordingly --- src/main/java/be/neutrinet/ispng/VPN.java | 1 - .../be/neutrinet/ispng/dns/DNSRecord.java | 19 ++-- .../neutrinet/ispng/dns/RequestHandler.java | 3 +- .../be/neutrinet/ispng/dns/ZoneBuilder.java | 15 +-- .../be/neutrinet/ispng/external/LDAP.java | 54 +++++----- .../java/be/neutrinet/ispng/i18n/I18N.java | 1 - .../be/neutrinet/ispng/mail/Generator.java | 1 - .../java/be/neutrinet/ispng/mail/Postman.java | 5 +- .../be/neutrinet/ispng/mail/Renderer.java | 7 +- .../be/neutrinet/ispng/monitoring/Agent.java | 2 +- .../ispng/openvpn/ManagementInterface.java | 2 +- .../ispng/openvpn/ObjectMarshall.java | 1 - .../be/neutrinet/ispng/security/Policy.java | 34 +----- .../ispng/security/SessionManager.java | 2 +- .../ispng/security/SessionToken.java | 3 +- .../be/neutrinet/ispng/util/DateUtil.java | 2 +- .../be/neutrinet/ispng/util/MariaDBType.java | 1 + .../java/be/neutrinet/ispng/vpn/Client.java | 6 +- .../be/neutrinet/ispng/vpn/ClientError.java | 1 - .../java/be/neutrinet/ispng/vpn/Clients.java | 3 +- .../be/neutrinet/ispng/vpn/Connection.java | 1 - .../be/neutrinet/ispng/vpn/Connections.java | 1 - .../be/neutrinet/ispng/vpn/Credential.java | 15 ++- .../be/neutrinet/ispng/vpn/Credentials.java | 4 +- .../neutrinet/ispng/vpn/TLSCertificate.java | 1 - .../java/be/neutrinet/ispng/vpn/User.java | 13 ++- .../java/be/neutrinet/ispng/vpn/Users.java | 75 ++++++++++--- .../ispng/vpn/admin/Registration.java | 4 +- .../ispng/vpn/admin/Registrations.java | 6 +- .../neutrinet/ispng/vpn/admin/UnlockKey.java | 2 +- .../neutrinet/ispng/vpn/admin/UnlockKeys.java | 4 +- .../neutrinet/ispng/vpn/api/FlowServlet.java | 1 - .../be/neutrinet/ispng/vpn/api/UnlockKey.java | 3 +- .../ispng/vpn/api/UserManagement.java | 25 ++--- .../ispng/vpn/api/UserPermissions.java | 6 +- .../neutrinet/ispng/vpn/api/UserSession.java | 6 +- .../be/neutrinet/ispng/vpn/api/VPNClient.java | 2 +- .../ispng/vpn/api/VPNClientConfig.java | 23 ++-- .../neutrinet/ispng/vpn/ca/Certificate.java | 2 +- .../java/com/tufar/IPCalculator/IPv4.java | 102 +++++++++--------- src/main/java/net/wgr/core/GenericsUtils.java | 13 ++- .../java/net/wgr/core/ReflectionUtils.java | 11 +- src/main/java/net/wgr/core/StringUtils.java | 7 +- 43 files changed, 240 insertions(+), 250 deletions(-) diff --git a/src/main/java/be/neutrinet/ispng/VPN.java b/src/main/java/be/neutrinet/ispng/VPN.java index 39a9cbc..1dee8fb 100644 --- a/src/main/java/be/neutrinet/ispng/VPN.java +++ b/src/main/java/be/neutrinet/ispng/VPN.java @@ -50,7 +50,6 @@ import java.util.Optional; import java.util.Properties; /** - * * @author wannes */ public class VPN implements Daemon { diff --git a/src/main/java/be/neutrinet/ispng/dns/DNSRecord.java b/src/main/java/be/neutrinet/ispng/dns/DNSRecord.java index 4d7757e..08cbb8d 100644 --- a/src/main/java/be/neutrinet/ispng/dns/DNSRecord.java +++ b/src/main/java/be/neutrinet/ispng/dns/DNSRecord.java @@ -14,6 +14,15 @@ import java.util.UUID; @DatabaseTable public class DNSRecord implements Serializable, OwnedEntity { + public final static String A = "A"; + public final static String AAAA = "AAAA"; + public final static String PTR = "PTR"; + public final static String NS = "NS"; + public final static String[] ALLOWED_TYPES = new String[]{A, AAAA, PTR, NS}; + @DatabaseField(foreign = true, foreignAutoRefresh = true) + public transient Client client; + @DatabaseField + public long lastModified; @DatabaseField(generatedId = true) private int id; @DatabaseField(canBeNull = false) @@ -24,16 +33,6 @@ public class DNSRecord implements Serializable, OwnedEntity { private int ttl; @DatabaseField(canBeNull = false) private String type; - @DatabaseField(foreign = true, foreignAutoRefresh = true) - public transient Client client; - @DatabaseField - public long lastModified; - - public final static String A = "A"; - public final static String AAAA = "AAAA"; - public final static String PTR = "PTR"; - public final static String NS = "NS"; - public final static String[] ALLOWED_TYPES = new String[]{A, AAAA, PTR, NS}; private DNSRecord() { diff --git a/src/main/java/be/neutrinet/ispng/dns/RequestHandler.java b/src/main/java/be/neutrinet/ispng/dns/RequestHandler.java index fcc00a5..4236925 100644 --- a/src/main/java/be/neutrinet/ispng/dns/RequestHandler.java +++ b/src/main/java/be/neutrinet/ispng/dns/RequestHandler.java @@ -16,10 +16,9 @@ import java.util.Map; */ public class RequestHandler { - private Map caches = new HashMap<>(); - static final int FLAG_DNSSECOK = 1; static final int FLAG_SIGONLY = 2; + private Map caches = new HashMap<>(); public Cache getCache(int dclass) { Cache c = caches.get(dclass); diff --git a/src/main/java/be/neutrinet/ispng/dns/ZoneBuilder.java b/src/main/java/be/neutrinet/ispng/dns/ZoneBuilder.java index 7ca0a71..0129674 100644 --- a/src/main/java/be/neutrinet/ispng/dns/ZoneBuilder.java +++ b/src/main/java/be/neutrinet/ispng/dns/ZoneBuilder.java @@ -19,15 +19,8 @@ import java.util.*; public class ZoneBuilder { private final static String PREFIX = "/ispng/dns/"; - private KeptMap zones; - private Map> records = new HashMap<>(); - // TODO persist zone serial number suffix - private Map suffixes = new HashMap<>(); private final static SimpleDateFormat SERIAL_NUMBER_FORMAT = new SimpleDateFormat("YYYYMMDD"); public static Name SAME_AS_ROOT; - private int ttl; - private List nameServers = new ArrayList<>(); - private Properties cfg; static { try { @@ -37,6 +30,14 @@ public class ZoneBuilder { } } + private KeptMap zones; + private Map> records = new HashMap<>(); + // TODO persist zone serial number suffix + private Map suffixes = new HashMap<>(); + private int ttl; + private List nameServers = new ArrayList<>(); + private Properties cfg; + public void boot(Properties cfg) { this.cfg = cfg; this.ttl = Integer.parseInt(cfg.getProperty("zone.all.record.TTL")); diff --git a/src/main/java/be/neutrinet/ispng/external/LDAP.java b/src/main/java/be/neutrinet/ispng/external/LDAP.java index dee4a70..c433da7 100644 --- a/src/main/java/be/neutrinet/ispng/external/LDAP.java +++ b/src/main/java/be/neutrinet/ispng/external/LDAP.java @@ -20,9 +20,9 @@ import java.util.Optional; * Created by wannes on 27/05/15. */ public class LDAP { + private final static LDAP instance = new LDAP(); private LDAPConnection connection; private Logger logger = Logger.getLogger(getClass()); - private final static LDAP instance = new LDAP(); private LDAP() { @@ -32,6 +32,32 @@ public class LDAP { return instance; } + public static String findAttributeName(Class clazz, String fieldName) { + assert clazz != null; + assert fieldName != null; + + try { + for (Field f : clazz.getDeclaredFields()) { + if (f.getName().equals(fieldName)) { + LDAPField field = f.getAnnotation(LDAPField.class); + if (field != null) { + return field.attribute(); + } else { + return fieldName; + } + } + } + } catch (Exception ex) { + Logger.getLogger(LDAP.class).error("Failed to find LDAP attribute for field " + fieldName, ex); + } + + return fieldName; + } + + public static LDAPConnection connection() { + return instance.connection; + } + public void boot() { Optional host = Config.get("ldap/host"); if (host.isPresent()) { @@ -76,30 +102,4 @@ public class LDAP { } } } - - public static String findAttributeName(Class clazz, String fieldName) { - assert clazz != null; - assert fieldName != null; - - try { - for (Field f : clazz.getDeclaredFields()) { - if (f.getName().equals(fieldName)) { - LDAPField field = f.getAnnotation(LDAPField.class); - if (field != null) { - return field.attribute(); - } else { - return fieldName; - } - } - } - } catch (Exception ex) { - Logger.getLogger(LDAP.class).error("Failed to find LDAP attribute for field " + fieldName, ex); - } - - return fieldName; - } - - public static LDAPConnection connection() { - return instance.connection; - } } diff --git a/src/main/java/be/neutrinet/ispng/i18n/I18N.java b/src/main/java/be/neutrinet/ispng/i18n/I18N.java index 349b7c9..9a6573c 100644 --- a/src/main/java/be/neutrinet/ispng/i18n/I18N.java +++ b/src/main/java/be/neutrinet/ispng/i18n/I18N.java @@ -11,7 +11,6 @@ import java.util.logging.Level; import java.util.logging.Logger; /** - * * @author wannes */ public class I18N { diff --git a/src/main/java/be/neutrinet/ispng/mail/Generator.java b/src/main/java/be/neutrinet/ispng/mail/Generator.java index 49a8a3f..a78a761 100644 --- a/src/main/java/be/neutrinet/ispng/mail/Generator.java +++ b/src/main/java/be/neutrinet/ispng/mail/Generator.java @@ -26,7 +26,6 @@ import java.util.Iterator; import java.util.Map; /** - * * @author wannes */ public class Generator { diff --git a/src/main/java/be/neutrinet/ispng/mail/Postman.java b/src/main/java/be/neutrinet/ispng/mail/Postman.java index 3c55cb5..465196d 100644 --- a/src/main/java/be/neutrinet/ispng/mail/Postman.java +++ b/src/main/java/be/neutrinet/ispng/mail/Postman.java @@ -15,6 +15,7 @@ import java.util.Properties; /** * TODO: find out if there are any external services with similar functionality and remove this mail piece + * * @author wannes */ public class Postman { @@ -59,9 +60,9 @@ public class Postman { * Create MimeMessage using Gandi session * * @return MimeMessage created message - * @throws AddressException if the email address parse failed + * @throws AddressException if the email address parse failed * @throws MessagingException if the connection is dead or not in the - * connected state or if the message is not a MimeMessage + * connected state or if the message is not a MimeMessage */ public MimeMessage createNewMessage() throws AddressException, MessagingException { if (session == null) { diff --git a/src/main/java/be/neutrinet/ispng/mail/Renderer.java b/src/main/java/be/neutrinet/ispng/mail/Renderer.java index 13e9d4d..2508369 100644 --- a/src/main/java/be/neutrinet/ispng/mail/Renderer.java +++ b/src/main/java/be/neutrinet/ispng/mail/Renderer.java @@ -15,7 +15,6 @@ import java.util.HashMap; import java.util.Map; /** - * * @author wannes */ public class Renderer { @@ -28,16 +27,16 @@ public class Renderer { public String renderInTemplate(String segmentName, Map content, boolean plaintext) { fillInDefaults(content); - + String rseg = render(segmentName, content, plaintext); HashMap ct = new HashMap<>(); content.remove("body"); ct.putAll(content); ct.put("body", rseg); - + return render(BASE_TEMPLATE, ct, plaintext); } - + protected void fillInDefaults(Map content) { if (!content.containsKey("header-img-src")) { content.put("header-img-src", VPN.cfg.getProperty("mail.headerImageURL")); diff --git a/src/main/java/be/neutrinet/ispng/monitoring/Agent.java b/src/main/java/be/neutrinet/ispng/monitoring/Agent.java index 892932f..fc2ceb0 100644 --- a/src/main/java/be/neutrinet/ispng/monitoring/Agent.java +++ b/src/main/java/be/neutrinet/ispng/monitoring/Agent.java @@ -15,9 +15,9 @@ import java.util.concurrent.ConcurrentLinkedQueue; * Created by wannes on 10/2/14. */ public class Agent { + public static int MAX_BACKLOG = 1000; protected OpenTSDB api; protected ConcurrentLinkedQueue queue; - public static int MAX_BACKLOG = 1000; protected Timer timer; protected boolean busy; diff --git a/src/main/java/be/neutrinet/ispng/openvpn/ManagementInterface.java b/src/main/java/be/neutrinet/ispng/openvpn/ManagementInterface.java index 769d456..1af47c8 100644 --- a/src/main/java/be/neutrinet/ispng/openvpn/ManagementInterface.java +++ b/src/main/java/be/neutrinet/ispng/openvpn/ManagementInterface.java @@ -270,7 +270,7 @@ public class ManagementInterface implements Runnable { Logger.getLogger(getClass()).warn("Recovering from management interface failure"); // wait one second 'til recover attempt - Thread.sleep(1000); + Thread.sleep(10000000); } } } catch (Exception ex) { diff --git a/src/main/java/be/neutrinet/ispng/openvpn/ObjectMarshall.java b/src/main/java/be/neutrinet/ispng/openvpn/ObjectMarshall.java index 6acf890..13efe59 100644 --- a/src/main/java/be/neutrinet/ispng/openvpn/ObjectMarshall.java +++ b/src/main/java/be/neutrinet/ispng/openvpn/ObjectMarshall.java @@ -24,7 +24,6 @@ import java.lang.reflect.Field; import java.util.Map; /** - * * @author wannes */ public class ObjectMarshall { diff --git a/src/main/java/be/neutrinet/ispng/security/Policy.java b/src/main/java/be/neutrinet/ispng/security/Policy.java index af5afeb..0371940 100644 --- a/src/main/java/be/neutrinet/ispng/security/Policy.java +++ b/src/main/java/be/neutrinet/ispng/security/Policy.java @@ -1,6 +1,6 @@ package be.neutrinet.ispng.security; -import be.neutrinet.ispng.VPN; +import be.neutrinet.ispng.vpn.Users; import java.util.ArrayList; import java.util.List; @@ -30,38 +30,10 @@ public class Policy { } public boolean canAccess(UUID user, OwnedEntity entity) { - return !(entity == null || user == null) && (isAdmin(user) || entity.isOwnedBy(user)); + return !(entity == null || user == null) && (Users.isAdmin(user) || entity.isOwnedBy(user)); } public boolean canModify(UUID user, OwnedEntity entity) { - return !(entity == null || user == null) && (isAdmin(user) || entity.isOwnedBy(user)); - } - - public final boolean isAdmin(UUID user) { - if (VPN.cfg.getProperty("users.admin") == null) return false; - - boolean match = false; - String[] str = VPN.cfg.getProperty("users.admin").split(";"); - for (String s : str) { - if (user.equals(UUID.fromString(s))) { - match = true; - } - } - - return match; - } - - public final boolean isRelatedService(UUID user) { - if (VPN.cfg.getProperty("users.service") == null) return false; - - boolean match = false; - String[] str = VPN.cfg.getProperty("users.service").split(";"); - for (String s : str) { - if (user.equals(UUID.fromString(s))) { - match = true; - } - } - - return match; + return !(entity == null || user == null) && (Users.isAdmin(user) || entity.isOwnedBy(user)); } } diff --git a/src/main/java/be/neutrinet/ispng/security/SessionManager.java b/src/main/java/be/neutrinet/ispng/security/SessionManager.java index 92cf0e6..fcf79c1 100644 --- a/src/main/java/be/neutrinet/ispng/security/SessionManager.java +++ b/src/main/java/be/neutrinet/ispng/security/SessionManager.java @@ -12,7 +12,7 @@ public class SessionManager { private static SessionManager instance = new SessionManager(); public static SessionToken createSessionToken(User user, String address) { - return new SessionToken(user.globalId, address); + return new SessionToken(user.id, address); } public static boolean validateToken(String token, String address) { diff --git a/src/main/java/be/neutrinet/ispng/security/SessionToken.java b/src/main/java/be/neutrinet/ispng/security/SessionToken.java index cfa7dd8..7373d68 100644 --- a/src/main/java/be/neutrinet/ispng/security/SessionToken.java +++ b/src/main/java/be/neutrinet/ispng/security/SessionToken.java @@ -1,5 +1,6 @@ package be.neutrinet.ispng.security; +import be.neutrinet.ispng.vpn.Users; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; import org.apache.log4j.Logger; @@ -55,7 +56,7 @@ public class SessionToken { } public boolean valid() { - if (Policy.get().isRelatedService(this.user)) return true; + if (Users.isRelatedService(this.user)) return true; return System.currentTimeMillis() - this.creationTime <= 3600 * 1000; diff --git a/src/main/java/be/neutrinet/ispng/util/DateUtil.java b/src/main/java/be/neutrinet/ispng/util/DateUtil.java index d6b97a7..c12b316 100644 --- a/src/main/java/be/neutrinet/ispng/util/DateUtil.java +++ b/src/main/java/be/neutrinet/ispng/util/DateUtil.java @@ -14,7 +14,7 @@ import java.util.Date; /** * Converts between LocalDateTime -> Date LocalDate -> Date Date -> * LocalDateTime - * + *

* Does not convert between Date -> LocalDate, risks loss of precision * * @author wannes diff --git a/src/main/java/be/neutrinet/ispng/util/MariaDBType.java b/src/main/java/be/neutrinet/ispng/util/MariaDBType.java index 8508945..1773f12 100644 --- a/src/main/java/be/neutrinet/ispng/util/MariaDBType.java +++ b/src/main/java/be/neutrinet/ispng/util/MariaDBType.java @@ -1,6 +1,7 @@ package be.neutrinet.ispng.util; // source http://stackoverflow.com/questions/14947832/ormlite-date-in-mysql-mariadb-with-millisecond-precision + import com.j256.ormlite.db.MysqlDatabaseType; import com.j256.ormlite.field.FieldType; diff --git a/src/main/java/be/neutrinet/ispng/vpn/Client.java b/src/main/java/be/neutrinet/ispng/vpn/Client.java index a5559cf..1eebc11 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/Client.java +++ b/src/main/java/be/neutrinet/ispng/vpn/Client.java @@ -46,13 +46,13 @@ public class Client implements OwnedEntity, Serializable { User user = users.get(0); HashMap query = new HashMap<>(); - query.put("user_id", user.globalId); + query.put("user_id", user.id); query.put("commonName", vpnClient.commonName); List clients = Clients.dao.queryForFieldValues(query); if (clients.size() > 1) { Logger.getLogger(Client.class).error("Multiple client definitions, user: " + vpnClient.username + - ", commonName: " + vpnClient.commonName); + ", commonName: " + vpnClient.commonName); return Optional.empty(); } @@ -75,7 +75,7 @@ public class Client implements OwnedEntity, Serializable { assert users.size() == 1; User user = users.get(0); - c.userId = user.globalId; + c.userId = user.id; c.enabled = true; Clients.dao.createIfNotExists(c); diff --git a/src/main/java/be/neutrinet/ispng/vpn/ClientError.java b/src/main/java/be/neutrinet/ispng/vpn/ClientError.java index 7ec1c81..0a605fe 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/ClientError.java +++ b/src/main/java/be/neutrinet/ispng/vpn/ClientError.java @@ -8,7 +8,6 @@ package be.neutrinet.ispng.vpn; import be.neutrinet.ispng.i18n.I18N; /** - * * @author wannes */ public class ClientError { diff --git a/src/main/java/be/neutrinet/ispng/vpn/Clients.java b/src/main/java/be/neutrinet/ispng/vpn/Clients.java index 1831ae4..21b4ac2 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/Clients.java +++ b/src/main/java/be/neutrinet/ispng/vpn/Clients.java @@ -13,6 +13,7 @@ import java.sql.SQLException; */ public class Clients { public final static Client NONE; + public static Dao dao; static { try { @@ -25,6 +26,4 @@ public class Clients { NONE = new Client(); NONE.id = -1; } - - public static Dao dao; } diff --git a/src/main/java/be/neutrinet/ispng/vpn/Connection.java b/src/main/java/be/neutrinet/ispng/vpn/Connection.java index 0fd7b12..32d4200 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/Connection.java +++ b/src/main/java/be/neutrinet/ispng/vpn/Connection.java @@ -27,7 +27,6 @@ import java.util.Collection; import java.util.Date; /** - * * @author wannes */ @DatabaseTable(tableName = "ovpn_connections") diff --git a/src/main/java/be/neutrinet/ispng/vpn/Connections.java b/src/main/java/be/neutrinet/ispng/vpn/Connections.java index eb68661..1550907 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/Connections.java +++ b/src/main/java/be/neutrinet/ispng/vpn/Connections.java @@ -26,7 +26,6 @@ import org.apache.log4j.Logger; import java.sql.SQLException; /** - * * @author wannes */ public class Connections { diff --git a/src/main/java/be/neutrinet/ispng/vpn/Credential.java b/src/main/java/be/neutrinet/ispng/vpn/Credential.java index 5a60c4f..10ae352 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/Credential.java +++ b/src/main/java/be/neutrinet/ispng/vpn/Credential.java @@ -10,27 +10,26 @@ import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; /** - * * @author wannes */ @DatabaseTable(tableName = "user_credentials") public class Credential { - + @DatabaseField(generatedId = true) public int id; - - @DatabaseField(canBeNull = false, foreignColumnName = "id") + + @DatabaseField(canBeNull = false, foreignColumnName = "id") public User user; - + @DatabaseField(canBeNull = false, defaultValue = "GLOBAL") public String realm; - + @DatabaseField(canBeNull = false) public String type; - + @DatabaseField(canBeNull = false, defaultValue = "GRANT") public Modifier modifier; - + public enum Modifier { GRANT, DENY, INACTIVE } diff --git a/src/main/java/be/neutrinet/ispng/vpn/Credentials.java b/src/main/java/be/neutrinet/ispng/vpn/Credentials.java index dfffef0..6a39806 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/Credentials.java +++ b/src/main/java/be/neutrinet/ispng/vpn/Credentials.java @@ -9,11 +9,11 @@ import be.neutrinet.ispng.VPN; import com.j256.ormlite.dao.Dao; import com.j256.ormlite.dao.DaoManager; import com.j256.ormlite.table.TableUtils; -import java.sql.SQLException; import org.apache.log4j.Logger; +import java.sql.SQLException; + /** - * * @author wannes */ public class Credentials { diff --git a/src/main/java/be/neutrinet/ispng/vpn/TLSCertificate.java b/src/main/java/be/neutrinet/ispng/vpn/TLSCertificate.java index 7a6fcc9..293e846 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/TLSCertificate.java +++ b/src/main/java/be/neutrinet/ispng/vpn/TLSCertificate.java @@ -18,7 +18,6 @@ package be.neutrinet.ispng.vpn; /** - * * @author wannes */ public class TLSCertificate { diff --git a/src/main/java/be/neutrinet/ispng/vpn/User.java b/src/main/java/be/neutrinet/ispng/vpn/User.java index 89cd5ea..3a6a0f4 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/User.java +++ b/src/main/java/be/neutrinet/ispng/vpn/User.java @@ -28,7 +28,6 @@ import java.util.Date; import java.util.UUID; /** - * * @author wannes */ @LDAPObject(requestAllAttributes = true, structuralClass = "inetOrgPerson", auxiliaryClass = {"ispngAccount", "extensibleObject"}) @@ -37,7 +36,7 @@ public class User implements OwnedEntity { // Currently allowed countries = benelux public transient final String[] ALLOWED_COUNTRIES = new String[]{"BELGIUM", "NETHERLANDS", "LUXEMBOURG"}; @LDAPField(attribute = "uid", objectClass = "inetOrgPerson", requiredForEncode = true) - public UUID globalId; + public UUID id; @LDAPField(attribute = "mail", inRDN = true, requiredForEncode = true) public String email; @LDAPField(attribute = "givenName", objectClass = "inetOrgPerson", requiredForEncode = true) @@ -65,7 +64,7 @@ public class User implements OwnedEntity { private transient UserSettings settings; public User() { - this.globalId = UUID.randomUUID(); + this.id = UUID.randomUUID(); } @LDAPGetter(attribute = "cn") @@ -117,7 +116,7 @@ public class User implements OwnedEntity { public UserSettings settings() { if (settings == null) { - settings = new UserSettings("" + globalId); + settings = new UserSettings("" + id); settings.load(); } @@ -126,7 +125,7 @@ public class User implements OwnedEntity { @Override public boolean isOwnedBy(UUID user) { - return user != null && user.equals(globalId); + return user != null && user.equals(id); } @Override @@ -136,12 +135,12 @@ public class User implements OwnedEntity { User user = (User) o; - return globalId.equals(user.globalId); + return id.equals(user.id); } @Override public int hashCode() { - return globalId.hashCode(); + return id.hashCode(); } } diff --git a/src/main/java/be/neutrinet/ispng/vpn/Users.java b/src/main/java/be/neutrinet/ispng/vpn/Users.java index 603d814..fae4f1a 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/Users.java +++ b/src/main/java/be/neutrinet/ispng/vpn/Users.java @@ -33,7 +33,6 @@ import java.util.Optional; import java.util.UUID; /** - * * @author wannes */ public class Users { @@ -41,6 +40,18 @@ public class Users { public static LDAPPersister persister; public static User NOBODY; + static { + Class cls = User.class; + try { + persister = LDAPPersister.getInstance(cls); + } catch (LDAPPersistException ex) { + org.apache.log4j.Logger.getLogger(cls).error("Failed to create LDAP persister", ex); + } + + NOBODY = new User(); + NOBODY.id = UUID.fromString("00000000-0000-0000-0000-000000000000"); + } + public final static User authenticate(String email, String password) { List users = query("email", email); @@ -48,9 +59,7 @@ public class Users { if (users.size() == 1) { User user = users.get(0); - String salt = BCrypt.gensalt(10); - String pwd = BCrypt.hashpw(password, salt); - if (user.getPassword().equals(pwd)) { + if (BCrypt.checkpw(password, user.getPassword())) { return user; } } @@ -150,22 +159,56 @@ public class Users { return user; } + public static boolean isAdmin(UUID user) { + try { + String filter = "(&(member=" + queryForId(user).getDN() + ")(objectClass=groupOfNames))"; + SearchResult searchResult = LDAP.connection().search( + "dc=neutrinet,dc=be", + SearchScope.SUB, + DereferencePolicy.ALWAYS, + Integer.MAX_VALUE, + 0, + false, + Filter.create(filter)); + + for (SearchResultEntry sre : searchResult.getSearchEntries()) { + if (sre.getAttribute("cn").getValue().equals("Administrators")) + return true; + } + } catch (LDAPException ex) { + Logger.getLogger(Users.class).error("Failed to get group memberships for user " + user, ex); + } + + return false; + } + + public static boolean isRelatedService(UUID user) { + try { + String filter = "(&(member=" + queryForId(user).getDN() + ")(objectClass=groupOfNames))"; + SearchResult searchResult = LDAP.connection().search( + "dc=neutrinet,dc=be", + SearchScope.SUB, + DereferencePolicy.ALWAYS, + Integer.MAX_VALUE, + 0, + false, + Filter.create(filter)); + + for (SearchResultEntry sre : searchResult.getSearchEntries()) { + if (sre.getAttribute("cn").getValue().equals("ServiceUsers")) + return true; + } + } catch (LDAPException ex) { + Logger.getLogger(Users.class).error("Failed to get group memberships for user " + user, ex); + } + + return false; + } + protected static String usersDN() { Optional dn = Config.get().getValue("ldap/users/dn"); if (!dn.isPresent()) { throw new IllegalArgumentException("No LDAP users DN set"); } else return dn.get(); } - - static { - Class cls = User.class; - try { - persister = LDAPPersister.getInstance(cls); - } catch (LDAPPersistException ex) { - org.apache.log4j.Logger.getLogger(cls).error("Failed to create LDAP persister", ex); - } - - NOBODY = new User(); - NOBODY.globalId = UUID.fromString("00000000-0000-0000-0000-000000000000"); - } } diff --git a/src/main/java/be/neutrinet/ispng/vpn/admin/Registration.java b/src/main/java/be/neutrinet/ispng/vpn/admin/Registration.java index f2a5091..fcbeb4b 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/admin/Registration.java +++ b/src/main/java/be/neutrinet/ispng/vpn/admin/Registration.java @@ -31,7 +31,6 @@ public class Registration { private static final Map activeRegistrations = new HashMap<>(); @DatabaseField(canBeNull = false) public UUID user; - private User cachedUser; @DatabaseField(foreign = true, foreignAutoRefresh = true) public Client client; @DatabaseField(canBeNull = false) @@ -44,6 +43,7 @@ public class Registration { public UnlockKey unlockKey; @DatabaseField public Date completed; + private User cachedUser; @DatabaseField(id = true, canBeNull = false) private UUID id; @@ -122,6 +122,6 @@ public class Registration { public void setUser(User user) { cachedUser = user; - this.user = user.globalId; + this.user = user.id; } } diff --git a/src/main/java/be/neutrinet/ispng/vpn/admin/Registrations.java b/src/main/java/be/neutrinet/ispng/vpn/admin/Registrations.java index 37bd318..630e4f6 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/admin/Registrations.java +++ b/src/main/java/be/neutrinet/ispng/vpn/admin/Registrations.java @@ -10,15 +10,15 @@ import be.neutrinet.ispng.VPN; import com.j256.ormlite.dao.Dao; import com.j256.ormlite.dao.DaoManager; import com.j256.ormlite.table.TableUtils; -import java.sql.SQLException; import org.apache.log4j.Logger; +import java.sql.SQLException; + /** - * * @author wannes */ public class Registrations { - public static Dao dao; + public static Dao dao; static { Class cls = Registration.class; diff --git a/src/main/java/be/neutrinet/ispng/vpn/admin/UnlockKey.java b/src/main/java/be/neutrinet/ispng/vpn/admin/UnlockKey.java index 5f0d3d1..e31a5c2 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/admin/UnlockKey.java +++ b/src/main/java/be/neutrinet/ispng/vpn/admin/UnlockKey.java @@ -7,10 +7,10 @@ package be.neutrinet.ispng.vpn.admin; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; + import java.util.Date; /** - * * @author wannes */ @DatabaseTable(tableName = "vpn_unlock_keys") diff --git a/src/main/java/be/neutrinet/ispng/vpn/admin/UnlockKeys.java b/src/main/java/be/neutrinet/ispng/vpn/admin/UnlockKeys.java index 3ea6102..0c1dde2 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/admin/UnlockKeys.java +++ b/src/main/java/be/neutrinet/ispng/vpn/admin/UnlockKeys.java @@ -9,11 +9,11 @@ import be.neutrinet.ispng.VPN; import com.j256.ormlite.dao.Dao; import com.j256.ormlite.dao.DaoManager; import com.j256.ormlite.table.TableUtils; -import java.sql.SQLException; import org.apache.log4j.Logger; +import java.sql.SQLException; + /** - * * @author wannes */ public class UnlockKeys { diff --git a/src/main/java/be/neutrinet/ispng/vpn/api/FlowServlet.java b/src/main/java/be/neutrinet/ispng/vpn/api/FlowServlet.java index a02d98c..cb47ffc 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/api/FlowServlet.java +++ b/src/main/java/be/neutrinet/ispng/vpn/api/FlowServlet.java @@ -22,7 +22,6 @@ import java.sql.SQLException; import java.util.UUID; /** - * * @author wannes */ public class FlowServlet extends HttpServlet { diff --git a/src/main/java/be/neutrinet/ispng/vpn/api/UnlockKey.java b/src/main/java/be/neutrinet/ispng/vpn/api/UnlockKey.java index 48ec04d..d9a0f8d 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/api/UnlockKey.java +++ b/src/main/java/be/neutrinet/ispng/vpn/api/UnlockKey.java @@ -21,7 +21,6 @@ import java.util.List; import java.util.Map; /** - * * @author wannes */ public class UnlockKey extends ResourceBase { @@ -74,7 +73,7 @@ public class UnlockKey extends ResourceBase { List keys = UnlockKeys.dao.queryForEq("email", data.get("email")); UnlockKeys.dao.delete(keys); - + return DEFAULT_SUCCESS; } catch (Exception ex) { Logger.getLogger(getClass()).error("Failed to delete unlock key", ex); diff --git a/src/main/java/be/neutrinet/ispng/vpn/api/UserManagement.java b/src/main/java/be/neutrinet/ispng/vpn/api/UserManagement.java index f1c6a0e..f6ebef8 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/api/UserManagement.java +++ b/src/main/java/be/neutrinet/ispng/vpn/api/UserManagement.java @@ -21,7 +21,6 @@ import java.util.Optional; import java.util.UUID; /** - * * @author wannes */ public class UserManagement extends ResourceBase { @@ -38,21 +37,13 @@ public class UserManagement extends ResourceBase { } String id = getAttribute("user"); + User user = Users.queryForId(UUID.fromString(id)); - User user; - - List users = Users.query("globalId", UUID.fromString(id)); - if (users.isEmpty()) { - return clientError("NO_SUCH_OBJECT", Status.SUCCESS_NO_CONTENT); - } else { - user = users.get(0); - } - - if (Policy.get().canAccess(getSessionToken().get().getUser(), user)) { - return new JacksonRepresentation(user); - } else { - return clientError("FORBIDDEN", Status.CLIENT_ERROR_BAD_REQUEST); - } + if (Policy.get().canAccess(getSessionToken().get().getUser(), user)) { + return new JacksonRepresentation(user); + } else { + return clientError("FORBIDDEN", Status.CLIENT_ERROR_BAD_REQUEST); + } } catch (Exception ex) { Logger.getLogger(getClass()).error("Failed to retrieve users", ex); @@ -60,7 +51,7 @@ public class UserManagement extends ResourceBase { return DEFAULT_ERROR; } - + @Post public Representation update(User user) { if (!sessionAvailable()) return DEFAULT_ERROR; @@ -70,7 +61,7 @@ public class UserManagement extends ResourceBase { return clientError("MALFORMED_REQUEST", Status.CLIENT_ERROR_BAD_REQUEST); } UUID userId = UUID.fromString(getAttribute("user")); - if (!userId.equals(user.globalId)) { + if (!userId.equals(user.id)) { return clientError("MALFORMED_REQUEST", Status.CLIENT_ERROR_BAD_REQUEST); } diff --git a/src/main/java/be/neutrinet/ispng/vpn/api/UserPermissions.java b/src/main/java/be/neutrinet/ispng/vpn/api/UserPermissions.java index fd0378e..89cf503 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/api/UserPermissions.java +++ b/src/main/java/be/neutrinet/ispng/vpn/api/UserPermissions.java @@ -26,7 +26,7 @@ public class UserPermissions extends ResourceBase { return clientError("UNAUTHORIZED", Status.CLIENT_ERROR_FORBIDDEN); Permissions permissions = new Permissions(); - permissions.build(user.globalId); + permissions.build(user.id); return new JacksonRepresentation<>(permissions); } @@ -35,8 +35,8 @@ public class UserPermissions extends ResourceBase { public boolean isService; public void build(UUID user) { - this.isAdmin = Policy.get().isAdmin(user); - this.isService = Policy.get().isRelatedService(user); + this.isAdmin = Users.isAdmin(user); + this.isService = Users.isRelatedService(user); } } } diff --git a/src/main/java/be/neutrinet/ispng/vpn/api/UserSession.java b/src/main/java/be/neutrinet/ispng/vpn/api/UserSession.java index 085ab2f..89cb36f 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/api/UserSession.java +++ b/src/main/java/be/neutrinet/ispng/vpn/api/UserSession.java @@ -1,8 +1,8 @@ package be.neutrinet.ispng.vpn.api; -import be.neutrinet.ispng.security.Policy; import be.neutrinet.ispng.security.SessionToken; import be.neutrinet.ispng.security.SessionTokens; +import be.neutrinet.ispng.vpn.Users; import org.apache.log4j.Logger; import org.restlet.data.Status; import org.restlet.ext.jackson.JacksonRepresentation; @@ -18,7 +18,7 @@ import java.util.UUID; public class UserSession extends ResourceBase { @Get public Representation getSessionDetails() { - if (!Policy.get().isRelatedService(getLoggedInUser())) + if (!Users.isRelatedService(getLoggedInUser())) return clientError("ACCESS_DENIED", Status.CLIENT_ERROR_UNAUTHORIZED); if (getAttribute("session") == null) return clientError("INVALID_REQUEST", Status.CLIENT_ERROR_BAD_REQUEST); @@ -27,7 +27,7 @@ public class UserSession extends ResourceBase { HashMap sessionDetails = new HashMap<>(); SessionToken st = SessionTokens.dao.queryForEq("token", UUID.fromString(session)).get(0); sessionDetails.put("details", st); - sessionDetails.put("isAdmin", Policy.get().isAdmin(st.getUser())); + sessionDetails.put("isAdmin", Users.isAdmin(st.getUser())); return new JacksonRepresentation<>(sessionDetails); } catch (Exception ex) { Logger.getLogger(getClass()).error("Failed to retrieve session", ex); diff --git a/src/main/java/be/neutrinet/ispng/vpn/api/VPNClient.java b/src/main/java/be/neutrinet/ispng/vpn/api/VPNClient.java index 241fb2d..b4ac170 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/api/VPNClient.java +++ b/src/main/java/be/neutrinet/ispng/vpn/api/VPNClient.java @@ -64,7 +64,7 @@ public class VPNClient extends ResourceBase { try { if (getRequestAttributes().containsKey("client")) if (!getAttribute("client").toLowerCase().equals("all")) - return new JacksonRepresentation<>(Clients.dao.queryForId(getAttribute("client"))); + return new JacksonRepresentation<>(Clients.dao.queryForId(getAttribute("client"))); List clients; diff --git a/src/main/java/be/neutrinet/ispng/vpn/api/VPNClientConfig.java b/src/main/java/be/neutrinet/ispng/vpn/api/VPNClientConfig.java index b5df8a4..2603c1f 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/api/VPNClientConfig.java +++ b/src/main/java/be/neutrinet/ispng/vpn/api/VPNClientConfig.java @@ -35,21 +35,20 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; /** - * * @author wannes */ public class VPNClientConfig extends ResourceBase { public final static String[] DEFAULTS = new String[]{ - "client", - "dev tun", + "client", + "dev tun", "proto udp", - "remote " + VPN.cfg.getProperty("openvpn.publicaddress") + ' ' + VPN.cfg.getProperty("openvpn.publicport"), - "resolv-retry infinite", - "nobind", - "ns-cert-type server", - "comp-lzo", - "ca ca.crt", + "remote " + VPN.cfg.getProperty("openvpn.publicaddress") + ' ' + VPN.cfg.getProperty("openvpn.publicport"), + "resolv-retry infinite", + "nobind", + "ns-cert-type server", + "comp-lzo", + "ca ca.crt", "auth-user-pass", "topology subnet" }; @@ -98,7 +97,7 @@ public class VPNClientConfig extends ResourceBase { ArrayList config = new ArrayList<>(); config.addAll(Arrays.asList(DEFAULTS)); - + // create zip ByteArrayOutputStream baos = new ByteArrayOutputStream(); ZipOutputStream zip = new ZipOutputStream(baos); @@ -160,8 +159,8 @@ public class VPNClientConfig extends ResourceBase { rep.setDisposition(new Disposition(Disposition.TYPE_ATTACHMENT)); return rep; } - - protected Representation addPKCS11config (String platform, List config, User user) { + + protected Representation addPKCS11config(String platform, List config, User user) { switch (platform) { case "linux": config.add("pkcs11-providers /usr/lib/libbeidpkcs11.so"); diff --git a/src/main/java/be/neutrinet/ispng/vpn/ca/Certificate.java b/src/main/java/be/neutrinet/ispng/vpn/ca/Certificate.java index c9122fa..4e81ab4 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/ca/Certificate.java +++ b/src/main/java/be/neutrinet/ispng/vpn/ca/Certificate.java @@ -75,7 +75,7 @@ public class Certificate { return null; } - + public byte[] getRaw() { String crtPath = VPN.cfg.getProperty("ca.storeDir", "ca") + "/" + serial + ".crt"; File crt = new File(crtPath); diff --git a/src/main/java/com/tufar/IPCalculator/IPv4.java b/src/main/java/com/tufar/IPCalculator/IPv4.java index 1fda164..2d0c6f9 100644 --- a/src/main/java/com/tufar/IPCalculator/IPv4.java +++ b/src/main/java/com/tufar/IPCalculator/IPv4.java @@ -156,6 +156,54 @@ public class IPv4 { netmaskNumeric = netmaskNumeric << (32 - numericCIDR); } + /** + * @param args + */ + public static void main(String[] args) { + // ipv4.setIP("10.20.30.5", "255.255.255.200"); + // System.out.println(ipv4.getIP()); + // System.out.println(ipv4.getNetmask()); + // System.out.println(ipv4.getCIDR()); + + /* + * IPv4 ipv4 = new IPv4("10.1.17.0/20"); + * System.out.println(ipv4.getIP()); + * System.out.println(ipv4.getNetmask()); + * System.out.println(ipv4.getCIDR()); + * + * System.out.println("============= Available IPs ==============="); + * List availableIPs = ipv4.getAvailableIPs(); int counter=0; + * for (String ip : availableIPs) { System.out.print(ip); + * System.out.print(" "); counter++; if((counter%10)==0) + * System.out.print("\n"); } + */ + IPv4 ipv4 = new IPv4("12.12.12.0/16"); + IPv4 ipv4Child = new IPv4("12.12.12.0/17"); + // IPv4 ipv4 = new IPv4("192.168.20.0/16"); + // System.out.println(ipv4.getIP()); + // System.out.println(ipv4.getNetmask()); + // System.out.println(ipv4.getCIDR()); + // System.out.println("======= MATCHES ======="); + // System.out.println(ipv4.getBinary(ipv4.baseIPnumeric)); + // System.out.println(ipv4.getBinary(ipv4.netmaskNumeric)); + + System.out.println(ipv4.contains(ipv4Child)); + + System.out.println(ipv4.getBinary(ipv4.baseIPnumeric)); + System.out.println(ipv4.getBinary(ipv4.netmaskNumeric)); + + System.out.println(ipv4Child.getBinary(ipv4Child.baseIPnumeric)); + System.out.println(ipv4Child.getBinary(ipv4Child.netmaskNumeric)); + System.out.println("==============output================"); + System.out.println(ipv4.contains(ipv4Child)); + // ipv4.contains("192.168.50.11"); + // System.out.println("======= DOES NOT MATCH ======="); + // ipv4.contains("10.2.3.4"); + // System.out.println(ipv4.validateIPAddress()); + // System.out.println(ipv4.getBinary(ipv4.baseIPnumeric)); + // System.out.println(ipv4.getBinary(ipv4.netmaskNumeric)); + } + /** * Get the IP in symbolic form, i.e. xxx.xxx.xxx.xxx * @@ -414,9 +462,9 @@ public class IPv4 { } /** - * @author Nico Coetzee * @param lowBoundary * @return + * @author Nico Coetzee */ private String getBoundaryAddr(boolean lowBoundary) { String result = ""; @@ -434,69 +482,21 @@ public class IPv4 { } /** - * @author Nico Coetzee * @param lowBoundary * @return the first IP address in the IP range + * @author Nico Coetzee */ public String getFirstIPAddr() { return getBoundaryAddr(true); } /** - * @author Nico Coetzee * @param lowBoundary * @return the last IP address in the IP range + * @author Nico Coetzee */ public String getLastIPAddr() { return getBoundaryAddr(false); } - /** - * @param args - */ - public static void main(String[] args) { - // ipv4.setIP("10.20.30.5", "255.255.255.200"); - // System.out.println(ipv4.getIP()); - // System.out.println(ipv4.getNetmask()); - // System.out.println(ipv4.getCIDR()); - - /* - * IPv4 ipv4 = new IPv4("10.1.17.0/20"); - * System.out.println(ipv4.getIP()); - * System.out.println(ipv4.getNetmask()); - * System.out.println(ipv4.getCIDR()); - * - * System.out.println("============= Available IPs ==============="); - * List availableIPs = ipv4.getAvailableIPs(); int counter=0; - * for (String ip : availableIPs) { System.out.print(ip); - * System.out.print(" "); counter++; if((counter%10)==0) - * System.out.print("\n"); } - */ - IPv4 ipv4 = new IPv4("12.12.12.0/16"); - IPv4 ipv4Child = new IPv4("12.12.12.0/17"); - // IPv4 ipv4 = new IPv4("192.168.20.0/16"); - // System.out.println(ipv4.getIP()); - // System.out.println(ipv4.getNetmask()); - // System.out.println(ipv4.getCIDR()); - // System.out.println("======= MATCHES ======="); - // System.out.println(ipv4.getBinary(ipv4.baseIPnumeric)); - // System.out.println(ipv4.getBinary(ipv4.netmaskNumeric)); - - System.out.println(ipv4.contains(ipv4Child)); - - System.out.println(ipv4.getBinary(ipv4.baseIPnumeric)); - System.out.println(ipv4.getBinary(ipv4.netmaskNumeric)); - - System.out.println(ipv4Child.getBinary(ipv4Child.baseIPnumeric)); - System.out.println(ipv4Child.getBinary(ipv4Child.netmaskNumeric)); - System.out.println("==============output================"); - System.out.println(ipv4.contains(ipv4Child)); - // ipv4.contains("192.168.50.11"); - // System.out.println("======= DOES NOT MATCH ======="); - // ipv4.contains("10.2.3.4"); - // System.out.println(ipv4.validateIPAddress()); - // System.out.println(ipv4.getBinary(ipv4.baseIPnumeric)); - // System.out.println(ipv4.getBinary(ipv4.netmaskNumeric)); - } - } diff --git a/src/main/java/net/wgr/core/GenericsUtils.java b/src/main/java/net/wgr/core/GenericsUtils.java index d616ac3..6d25ab4 100644 --- a/src/main/java/net/wgr/core/GenericsUtils.java +++ b/src/main/java/net/wgr/core/GenericsUtils.java @@ -13,9 +13,8 @@ import java.util.List; import java.util.Map; /** - * - * @created Jul 3, 2011 * @author wannes + * @created Jul 3, 2011 */ public class GenericsUtils { @@ -23,10 +22,10 @@ public class GenericsUtils { * Get the underlying class for a type, or null if the type is a variable * type. * - * @author Ian Robertson, - * http://www.artima.com/weblogs/viewpost.jsp?thread=208860 * @param type the type * @return the underlying class + * @author Ian Robertson, + * http://www.artima.com/weblogs/viewpost.jsp?thread=208860 */ public static Class getClass(Type type) { if (type instanceof Class) { @@ -50,11 +49,11 @@ public class GenericsUtils { * Get the actual type arguments a child class has used to extend a generic * base class. * - * @author Ian Robertson, - * http://www.artima.com/weblogs/viewpost.jsp?thread=208860 - * @param baseClass the base class + * @param baseClass the base class * @param childClass the child class * @return a list of the raw classes for the actual type arguments. + * @author Ian Robertson, + * http://www.artima.com/weblogs/viewpost.jsp?thread=208860 */ public static List> getTypeArguments( Class baseClass, Class childClass) { diff --git a/src/main/java/net/wgr/core/ReflectionUtils.java b/src/main/java/net/wgr/core/ReflectionUtils.java index 2046abe..090eb5d 100644 --- a/src/main/java/net/wgr/core/ReflectionUtils.java +++ b/src/main/java/net/wgr/core/ReflectionUtils.java @@ -21,9 +21,8 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; /** - * - * @created Jul 8, 2011 * @author wannes + * @created Jul 8, 2011 */ public class ReflectionUtils { @@ -109,12 +108,12 @@ public class ReflectionUtils { /** * Recursive method used to find all classes in a given directory. * - * @source http://snippets.dzone.com/posts/show/4831 - * @param directory The base directory + * @param directory The base directory * @param packageName The package name for classes found inside the base - * directory + * directory * @return The classes * @throws ClassNotFoundException + * @source http://snippets.dzone.com/posts/show/4831 */ private static List findClasses(File directory, String packageName) throws ClassNotFoundException { List classes = new ArrayList<>(); @@ -148,7 +147,7 @@ public class ReflectionUtils { /** * Returns difference between instances * - * @param instance type + * @param instance type * @param original * @param changed * @return diff --git a/src/main/java/net/wgr/core/StringUtils.java b/src/main/java/net/wgr/core/StringUtils.java index 40a0156..c496565 100644 --- a/src/main/java/net/wgr/core/StringUtils.java +++ b/src/main/java/net/wgr/core/StringUtils.java @@ -8,13 +8,12 @@ public class StringUtils { /** * Only checks for positive numbers * http://stackoverflow.com/questions/1102891/how-to-check-if-a-string-is-a-numeric-type-in-java + * * @param str * @return */ - public static boolean isNumeric(String str) - { - for (char c : str.toCharArray()) - { + public static boolean isNumeric(String str) { + for (char c : str.toCharArray()) { if (!Character.isDigit(c)) return false; } return true; -- GitLab From aaab1a66ebdb2ca258dbc6e50c647951489ad157 Mon Sep 17 00:00:00 2001 From: wannes Date: Thu, 18 Jun 2015 19:24:57 +0200 Subject: [PATCH 06/13] Auth using LDAP by opening a connection to the server with the user --- .../be/neutrinet/ispng/external/LDAP.java | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/main/java/be/neutrinet/ispng/external/LDAP.java b/src/main/java/be/neutrinet/ispng/external/LDAP.java index c433da7..3b43910 100644 --- a/src/main/java/be/neutrinet/ispng/external/LDAP.java +++ b/src/main/java/be/neutrinet/ispng/external/LDAP.java @@ -1,10 +1,7 @@ package be.neutrinet.ispng.external; import be.neutrinet.ispng.config.Config; -import com.unboundid.ldap.sdk.BindRequest; -import com.unboundid.ldap.sdk.BindResult; -import com.unboundid.ldap.sdk.LDAPConnection; -import com.unboundid.ldap.sdk.SimpleBindRequest; +import com.unboundid.ldap.sdk.*; import com.unboundid.ldap.sdk.controls.PasswordExpiredControl; import com.unboundid.ldap.sdk.controls.PasswordExpiringControl; import com.unboundid.ldap.sdk.persist.LDAPField; @@ -23,6 +20,8 @@ public class LDAP { private final static LDAP instance = new LDAP(); private LDAPConnection connection; private Logger logger = Logger.getLogger(getClass()); + private SocketFactory socketFactory = null; + private Optional host = null; private LDAP() { @@ -59,11 +58,11 @@ public class LDAP { } public void boot() { - Optional host = Config.get("ldap/host"); + host = Config.get("ldap/host"); if (host.isPresent()) { try { SSLUtil sslUtil = new SSLUtil(null, new TrustAllTrustManager()); - SocketFactory socketFactory = sslUtil.createSSLSocketFactory(); + socketFactory = sslUtil.createSSLSocketFactory(); connection = new LDAPConnection(socketFactory, host.get(), Integer.parseInt(Config.get("ldap/port", "636"))); Optional dn = Config.get("ldap/bind/dn"); @@ -102,4 +101,18 @@ public class LDAP { } } } + + public boolean auth(String dn, String password) { + try { + connection = new LDAPConnection(socketFactory, host.get(), Integer.parseInt(Config.get("ldap/port", "636"))); + BindResult bind = connection.bind(dn, password); + boolean success = bind.getResultCode().equals(ResultCode.SUCCESS); + connection.close(); + return success; + } catch (Exception ex) { + Logger.getLogger(getClass()).debug("Failed to auth user " + dn, ex); + } + + return false; + } } -- GitLab From ecbbe4e25004ad6cd9f615cc7776fe8ffff40555 Mon Sep 17 00:00:00 2001 From: wannes Date: Thu, 18 Jun 2015 19:25:30 +0200 Subject: [PATCH 07/13] Update User classes for user with UID-based LDAP backend --- .../java/be/neutrinet/ispng/vpn/User.java | 35 ++++++++++++++----- .../java/be/neutrinet/ispng/vpn/Users.java | 24 ++++++++----- 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/src/main/java/be/neutrinet/ispng/vpn/User.java b/src/main/java/be/neutrinet/ispng/vpn/User.java index 3a6a0f4..2cc17d9 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/User.java +++ b/src/main/java/be/neutrinet/ispng/vpn/User.java @@ -21,11 +21,12 @@ import be.neutrinet.ispng.security.OwnedEntity; import com.unboundid.ldap.sdk.persist.LDAPField; import com.unboundid.ldap.sdk.persist.LDAPGetter; import com.unboundid.ldap.sdk.persist.LDAPObject; -import org.mindrot.jbcrypt.BCrypt; +import org.apache.log4j.Logger; +import org.bouncycastle.jce.provider.BouncyCastleProvider; -import java.util.Calendar; -import java.util.Date; -import java.util.UUID; +import java.security.MessageDigest; +import java.security.Security; +import java.util.*; /** * @author wannes @@ -76,13 +77,29 @@ public class User implements OwnedEntity { return "mail=" + email + "," + Users.usersDN(); } - public String getPassword() { - return password; + public void setPassword(String password) { + assert password != null; + + try { + Security.addProvider(new BouncyCastleProvider()); + + byte[] salt = new byte[4]; + new Random().nextBytes(salt); + + MessageDigest md = MessageDigest.getInstance("SHA-512", "BC"); + md.reset(); + md.update(salt); + byte[] digest = md.digest(password.getBytes()); + + this.password = "{ssha512}" + Base64.getEncoder().encodeToString(digest); + } catch (Exception ex) { + Logger.getLogger(getClass()).fatal("Failed to set password. This is a fatal error, shutting down", ex); + System.exit(1); + } } - public void setPassword(String password) { - String salt = BCrypt.gensalt(10); - this.password = BCrypt.hashpw(password, salt); + public String getPassword() { + return password; } public void setRawPassword(String hashedPassword) { diff --git a/src/main/java/be/neutrinet/ispng/vpn/Users.java b/src/main/java/be/neutrinet/ispng/vpn/Users.java index fae4f1a..7d6f257 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/Users.java +++ b/src/main/java/be/neutrinet/ispng/vpn/Users.java @@ -25,7 +25,6 @@ import com.unboundid.ldap.sdk.persist.LDAPPersister; import com.unboundid.ldap.sdk.persist.ObjectSearchListener; import com.unboundid.ldap.sdk.persist.PersistedObjects; import org.apache.log4j.Logger; -import org.mindrot.jbcrypt.BCrypt; import java.util.ArrayList; import java.util.List; @@ -52,16 +51,13 @@ public class Users { NOBODY.id = UUID.fromString("00000000-0000-0000-0000-000000000000"); } - public final static User authenticate(String email, String password) { + public static User authenticate(String email, String password) { - List users = query("email", email); - assert users.size() <= 1; + assert email != null; + assert password != null; - if (users.size() == 1) { - User user = users.get(0); - if (BCrypt.checkpw(password, user.getPassword())) { - return user; - } + if (LDAP.get().auth("mail=" + email + "," + usersDN(), password)) { + return get(email); } return null; @@ -101,6 +97,16 @@ public class Users { return users; } + public static User get(String email) { + try { + return persister.get("mail=" + email + "," + usersDN(), LDAP.connection()); + } catch (LDAPException ex) { + Logger.getLogger(Users.class).error("Failed to get user", ex); + } + + return null; + } + public static User queryForId(String id) { List users = query("uid", id); assert users.size() <= 1; -- GitLab From 1cdbf5d3ed837f459116ab00e772838da66c2f75 Mon Sep 17 00:00:00 2001 From: wannes Date: Thu, 18 Jun 2015 19:25:56 +0200 Subject: [PATCH 08/13] Add LDAP dependency --- pom.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 53cea83..d02a558 100644 --- a/pom.xml +++ b/pom.xml @@ -17,11 +17,6 @@ ormlite-jdbc 4.48 - - org.mindrot - jbcrypt - 0.3m - org.restlet.jse org.restlet @@ -209,6 +204,11 @@ raven-log4j 6.0.0 + + com.unboundid + unboundid-ldapsdk + 2.3.8 + -- GitLab From 07f784346e9e605f2d47c0d7c13fdafce16ea114 Mon Sep 17 00:00:00 2001 From: wannes Date: Wed, 1 Jul 2015 23:46:50 +0200 Subject: [PATCH 09/13] Fix password hashing --- src/main/java/be/neutrinet/ispng/vpn/User.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/be/neutrinet/ispng/vpn/User.java b/src/main/java/be/neutrinet/ispng/vpn/User.java index 2cc17d9..1003e21 100644 --- a/src/main/java/be/neutrinet/ispng/vpn/User.java +++ b/src/main/java/be/neutrinet/ispng/vpn/User.java @@ -24,6 +24,7 @@ import com.unboundid.ldap.sdk.persist.LDAPObject; import org.apache.log4j.Logger; import org.bouncycastle.jce.provider.BouncyCastleProvider; +import java.io.ByteArrayOutputStream; import java.security.MessageDigest; import java.security.Security; import java.util.*; @@ -35,7 +36,7 @@ import java.util.*; public class User implements OwnedEntity { // Currently allowed countries = benelux - public transient final String[] ALLOWED_COUNTRIES = new String[]{"BELGIUM", "NETHERLANDS", "LUXEMBOURG"}; + public transient final String[] ALLOWED_COUNTRIES = new String[]{"BE", "NL", "LU"}; @LDAPField(attribute = "uid", objectClass = "inetOrgPerson", requiredForEncode = true) public UUID id; @LDAPField(attribute = "mail", inRDN = true, requiredForEncode = true) @@ -88,8 +89,14 @@ public class User implements OwnedEntity { MessageDigest md = MessageDigest.getInstance("SHA-512", "BC"); md.reset(); + md.update(password.getBytes()); md.update(salt); - byte[] digest = md.digest(password.getBytes()); + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + outputStream.write(md.digest()); + outputStream.write(salt); + + byte[] digest = outputStream.toByteArray(); this.password = "{ssha512}" + Base64.getEncoder().encodeToString(digest); } catch (Exception ex) { -- GitLab From 776b85a62b2a446a970feb4738a5bbe756c6aeae Mon Sep 17 00:00:00 2001 From: wannes Date: Wed, 1 Jul 2015 23:47:25 +0200 Subject: [PATCH 10/13] Add PostgreSQL database type to fix SEQUENCE handling --- src/main/java/be/neutrinet/ispng/VPN.java | 6 +++ .../neutrinet/ispng/util/PostgreSQLType.java | 51 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 src/main/java/be/neutrinet/ispng/util/PostgreSQLType.java diff --git a/src/main/java/be/neutrinet/ispng/VPN.java b/src/main/java/be/neutrinet/ispng/VPN.java index 1dee8fb..b0a459a 100644 --- a/src/main/java/be/neutrinet/ispng/VPN.java +++ b/src/main/java/be/neutrinet/ispng/VPN.java @@ -24,6 +24,7 @@ import be.neutrinet.ispng.mail.Generator; import be.neutrinet.ispng.monitoring.Agent; import be.neutrinet.ispng.util.MariaDBType; import be.neutrinet.ispng.util.MySQLDBType; +import be.neutrinet.ispng.util.PostgreSQLType; import be.neutrinet.ispng.util.Zookeeper; import be.neutrinet.ispng.vpn.Manager; import be.neutrinet.ispng.vpn.api.FlowServlet; @@ -119,6 +120,11 @@ public class VPN implements Daemon { cfg.getProperty("db.user"), cfg.getProperty("db.password"), new MySQLDBType()); + } else if (cfg.get("db.uri").toString().contains("postgresql")) { + cs = new JdbcConnectionSource(cfg.getProperty("db.uri"), + cfg.getProperty("db.user"), + cfg.getProperty("db.password"), + new PostgreSQLType()); } else { cs = new JdbcConnectionSource(cfg.getProperty("db.uri"), cfg.getProperty("db.user"), diff --git a/src/main/java/be/neutrinet/ispng/util/PostgreSQLType.java b/src/main/java/be/neutrinet/ispng/util/PostgreSQLType.java new file mode 100644 index 0000000..214fd1b --- /dev/null +++ b/src/main/java/be/neutrinet/ispng/util/PostgreSQLType.java @@ -0,0 +1,51 @@ +package be.neutrinet.ispng.util; + +import com.j256.ormlite.db.PostgresDatabaseType; +import com.j256.ormlite.field.FieldType; + +import java.util.List; + +/** + * Created by wannes on 6/30/15. + *

+ * Apparently the built-in PostgreSQL class has either not been tested or is abandoned + * This class implements proper SEQUENCE creation and handling + */ +public class PostgreSQLType extends PostgresDatabaseType { + @Override + public void appendSelectNextValFromSequence(StringBuilder sb, String sequenceName) { + sb.append("SELECT NEXTVAL("); + sb.append('\'').append('\"').append(sequenceName).append('\"').append('\''); + sb.append(')'); + } + + @Override + protected void configureGeneratedIdSequence(StringBuilder sb, FieldType fieldType, List statementsBefore, + List additionalArgs, List queriesAfter) { + String sequenceName = fieldType.getGeneratedIdSequence(); + // added existence check + // !! this check will only detect if there is a something with the given name present, + // even though the object in question might not be a SEQUENCE + StringBuilder seqSb = new StringBuilder(); + seqSb.append("do $$\nBEGIN\n"); + seqSb.append("IF NOT EXISTS (SELECT 0 FROM pg_class where relname = '"); + seqSb.append(sequenceName); + seqSb.append("' )\n" + + "THEN\n" + + "CREATE SEQUENCE "); + appendEscapedEntityName(seqSb, sequenceName); + seqSb.append(";\nEND IF;\nEND\n$$"); + + statementsBefore.add(seqSb.toString()); + + sb.append("DEFAULT NEXTVAL("); + // postgres needed this special escaping for NEXTVAL('"sequence-name"') + sb.append('\'').append('\"').append(sequenceName).append('\"').append('\''); + sb.append(") "); + // could also be the type serial for auto-generated sequences + // 8.2 also have the returning insert statement + + configureId(sb, fieldType, statementsBefore, additionalArgs, queriesAfter); + } + +} -- GitLab From 94af1a5a49b8b9e5291e2ade9a9a7a208668cb1d Mon Sep 17 00:00:00 2001 From: wannes Date: Wed, 1 Jul 2015 23:50:57 +0200 Subject: [PATCH 11/13] Country values now need to be a two-char ISO code --- web/registration/reg-form.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/registration/reg-form.html b/web/registration/reg-form.html index 6a306fd..59e6fb7 100644 --- a/web/registration/reg-form.html +++ b/web/registration/reg-form.html @@ -18,9 +18,9 @@



Cannot find your country in this list? Have a look at -- GitLab From d1c4385e819d25dbc9b7c5b25d70893547d352aa Mon Sep 17 00:00:00 2001 From: wannes Date: Wed, 1 Jul 2015 23:51:33 +0200 Subject: [PATCH 12/13] Re-add support for signups with unlock keys. --- web/registration/start-with-key.html | 46 ++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 web/registration/start-with-key.html diff --git a/web/registration/start-with-key.html b/web/registration/start-with-key.html new file mode 100644 index 0000000..12aff2c --- /dev/null +++ b/web/registration/start-with-key.html @@ -0,0 +1,46 @@ +

Welcome, fellow traveler, on a new journey on the internet.

+

This website will enable you to create a VPN account to use the service. +
+ To control the amount of signups, we currently require you to have an unlock key + to be able to sign up. If you have not received such a key, and you're willing to do the following

+
    +
  • Use our service
  • +
  • Provide feedback
  • +
  • Accept that Neutrinet currently makes no guarantees about the functionality nor security + of its + service. We are providing a lot of effort to make the VPN stable and as secure as possible, but + please refrain from using our network for critical applications (webshop, comms provider). +
  • +
  • Have a drink with us! (we're people, too)
  • +
+ +

Contact + us (IRC or mail), and we will likely provide you with one if we still have capacity left.

+ +

Sign up

+

You have an unlock key. We are building a great VPN service. Let's do this.

+
+
+
+
+
+
+
+ +
+

Unlock key policy

+

Neutrinet ASBL keeps the right to hand out and retract unlock keys at its sole discretion. + We handle ad-hoc requests by following guidelines:

+ +
    +
  • First come, first serve
  • +
  • One key per person
  • +
  • Unlock keys are valid for 7 days, starting at the date of issuance
  • +
  • When re-applying, your request is placed at the end of the queue
  • +
  • When using the unlock key with an e-mail address other than the one it has been sent + to, please allow us some time to verify both email addresses are used by the same person. +
  • +
\ No newline at end of file -- GitLab From 176009e152feef2c08c8bf9a7345d4f2d0462986 Mon Sep 17 00:00:00 2001 From: wannes Date: Thu, 2 Jul 2015 00:06:03 +0200 Subject: [PATCH 13/13] Undo change to form --- web/registration/js/main.js | 2 +- web/registration/reg-form.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/web/registration/js/main.js b/web/registration/js/main.js index c09f396..ad72da6 100644 --- a/web/registration/js/main.js +++ b/web/registration/js/main.js @@ -535,7 +535,7 @@ function App() { app.preloader.hide(); app.content.show(); - $('#reg-form').submit(function () { + $('#reg').click(function () { var data = {}; var fields = $('#reg-form').children('input[type=text]'); diff --git a/web/registration/reg-form.html b/web/registration/reg-form.html index 81a9e6d..52ee9b0 100644 --- a/web/registration/reg-form.html +++ b/web/registration/reg-form.html @@ -25,7 +25,7 @@

Cannot find your country in this list? Have a look at FFDN's list of associative ISPs around the world!

- +