diff --git a/caosdb-proto b/caosdb-proto index 69733f6dc6ac4370fed0a38c59f17fa24a74425b..0aa6278dbdf5a18e1909050eedf8b2134b194810 160000 --- a/caosdb-proto +++ b/caosdb-proto @@ -1 +1 @@ -Subproject commit 69733f6dc6ac4370fed0a38c59f17fa24a74425b +Subproject commit 0aa6278dbdf5a18e1909050eedf8b2134b194810 diff --git a/src/main/java/org/caosdb/server/accessControl/CaosDBAuthorizingRealm.java b/src/main/java/org/caosdb/server/accessControl/CaosDBAuthorizingRealm.java index e10a0b29b38b2e246bde8c89c43a8b82a9307b7e..ef1c656bafc6aab034bbfa1c9e43d76994b572a4 100644 --- a/src/main/java/org/caosdb/server/accessControl/CaosDBAuthorizingRealm.java +++ b/src/main/java/org/caosdb/server/accessControl/CaosDBAuthorizingRealm.java @@ -63,7 +63,7 @@ public class CaosDBAuthorizingRealm extends AuthorizingRealm { // Find all roles which are associated with this principal in this realm. final Set<String> principalRoles = - UserSources.resolve((Principal) principals.getPrimaryPrincipal()); + UserSources.resolveRoles((Principal) principals.getPrimaryPrincipal()); if (principalRoles != null) { authzInfo.addRoles(principalRoles); } diff --git a/src/main/java/org/caosdb/server/accessControl/Role.java b/src/main/java/org/caosdb/server/accessControl/Role.java index 1a34b49974804ae202ceaf4044ff1f620eaa5d12..1938d9f18926601a9eb4a0fb081c9738d5c7f501 100644 --- a/src/main/java/org/caosdb/server/accessControl/Role.java +++ b/src/main/java/org/caosdb/server/accessControl/Role.java @@ -23,6 +23,8 @@ package org.caosdb.server.accessControl; import java.io.Serializable; +import java.util.LinkedList; +import org.caosdb.server.permissions.PermissionRule; import org.jdom2.Element; public class Role implements Serializable { @@ -30,6 +32,7 @@ public class Role implements Serializable { private static final long serialVersionUID = 8968219504349206982L; public String name = null; public String description = null; + public LinkedList<PermissionRule> permission_rules = null; public Element toElement() { final Element ret = new Element("Role"); diff --git a/src/main/java/org/caosdb/server/accessControl/UserSources.java b/src/main/java/org/caosdb/server/accessControl/UserSources.java index a7abd1405f3d566bb672befc86b853dcf2a17357..aabb5d9b93ea1b43c7ecd3b2e2b0794e4f751ab4 100644 --- a/src/main/java/org/caosdb/server/accessControl/UserSources.java +++ b/src/main/java/org/caosdb/server/accessControl/UserSources.java @@ -36,6 +36,7 @@ import org.caosdb.server.CaosDBServer; import org.caosdb.server.ServerProperties; import org.caosdb.server.entity.Message; import org.caosdb.server.permissions.Role; +import org.caosdb.server.transaction.LogUserVisitTransaction; import org.caosdb.server.transaction.RetrieveRoleTransaction; import org.caosdb.server.transaction.RetrieveUserTransaction; import org.caosdb.server.utils.ServerMessages; @@ -69,6 +70,7 @@ import org.slf4j.LoggerFactory; */ public class UserSources extends HashMap<String, UserSource> { + public static final String USERNAME_PASSWORD_AUTHENTICATION = "USERNAME_PASSWORD_AUTHENTICATION"; private static final Logger logger = LoggerFactory.getLogger(UserSources.class); public static final String KEY_DEFAULT_REALM = "defaultRealm"; public static final String KEY_REALMS = "realms"; @@ -206,8 +208,13 @@ public class UserSources extends HashMap<String, UserSource> { return instance.map.getSectionProperty(Ini.DEFAULT_SECTION_NAME, KEY_DEFAULT_REALM, "CaosDB"); } - // @todo Refactor name: resolveRoles(...)? - public static Set<String> resolve(final Principal principal) { + /** + * Return the roles of a given user. + * + * @param principal + * @return A set of role names. + */ + public static Set<String> resolveRoles(final Principal principal) { if (AnonymousAuthenticationToken.PRINCIPAL == principal) { // anymous has one role Set<String> roles = new HashSet<>(); @@ -251,7 +258,22 @@ public class UserSources extends HashMap<String, UserSource> { } final boolean isValid = instance.get(realm).isValid(username, password); - return isValid && isActive(realm, username); + + if (isValid && isActive(realm, username)) { + logUserVisit(realm, username, USERNAME_PASSWORD_AUTHENTICATION); + return true; + } + return false; + } + + public static void logUserVisit(String realm, String username, String type) { + try { + LogUserVisitTransaction t = + new LogUserVisitTransaction(System.currentTimeMillis(), realm, username, type); + t.execute(); + } catch (final Exception e) { + throw new AuthenticationException(e); + } } private static boolean isActive(final String realm, final String username) { diff --git a/src/main/java/org/caosdb/server/database/BackendTransaction.java b/src/main/java/org/caosdb/server/database/BackendTransaction.java index 1e627ebafa2d273fafbc1762c70877df3f8fc2b5..15be37bb077cd0ae0d0a55444597694e360e64b2 100644 --- a/src/main/java/org/caosdb/server/database/BackendTransaction.java +++ b/src/main/java/org/caosdb/server/database/BackendTransaction.java @@ -46,6 +46,7 @@ import org.caosdb.server.database.backend.implementation.MySQL.MySQLInsertTransa import org.caosdb.server.database.backend.implementation.MySQL.MySQLIsSubType; import org.caosdb.server.database.backend.implementation.MySQL.MySQLListRoles; import org.caosdb.server.database.backend.implementation.MySQL.MySQLListUsers; +import org.caosdb.server.database.backend.implementation.MySQL.MySQLLogUserVisit; import org.caosdb.server.database.backend.implementation.MySQL.MySQLRegisterSubDomain; import org.caosdb.server.database.backend.implementation.MySQL.MySQLRetrieveAll; import org.caosdb.server.database.backend.implementation.MySQL.MySQLRetrieveAllUncheckedFiles; @@ -103,6 +104,7 @@ import org.caosdb.server.database.backend.interfaces.InsertTransactionHistoryImp import org.caosdb.server.database.backend.interfaces.IsSubTypeImpl; import org.caosdb.server.database.backend.interfaces.ListRolesImpl; import org.caosdb.server.database.backend.interfaces.ListUsersImpl; +import org.caosdb.server.database.backend.interfaces.LogUserVisitImpl; import org.caosdb.server.database.backend.interfaces.RegisterSubDomainImpl; import org.caosdb.server.database.backend.interfaces.RetrieveAllImpl; import org.caosdb.server.database.backend.interfaces.RetrieveAllUncheckedFilesImpl; @@ -210,6 +212,7 @@ public abstract class BackendTransaction implements Undoable { setImpl(RetrieveVersionHistoryImpl.class, MySQLRetrieveVersionHistory.class); setImpl(SetFileChecksumImpl.class, MySQLSetFileChecksum.class); setImpl(ListUsersImpl.class, MySQLListUsers.class); + setImpl(LogUserVisitImpl.class, MySQLLogUserVisit.class); } } diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLLogUserVisit.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLLogUserVisit.java new file mode 100644 index 0000000000000000000000000000000000000000..caa5f167df1fc2ffefbfaba4e769052ce3836c20 --- /dev/null +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLLogUserVisit.java @@ -0,0 +1,32 @@ +package org.caosdb.server.database.backend.implementation.MySQL; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import org.caosdb.server.database.access.Access; +import org.caosdb.server.database.backend.interfaces.LogUserVisitImpl; +import org.caosdb.server.database.exceptions.TransactionException; + +public class MySQLLogUserVisit extends MySQLTransaction implements LogUserVisitImpl { + + public MySQLLogUserVisit(Access access) { + super(access); + } + + public static final String LOG_USER_VISIT = + "INSERT IGNORE INTO user_info (status, realm, name) VALUES ('ACTIVE',?,?)"; + + @Override + public void log(long timestamp, String realm, String username, String type) { + try { + // TODO actually log the user visit + final PreparedStatement stmt = prepareStatement(LOG_USER_VISIT); + stmt.setString(1, realm); + stmt.setString(2, username); + stmt.execute(); + } catch (final SQLException e) { + throw new TransactionException(e); + } catch (final ConnectionException e) { + throw new TransactionException(e); + } + } +} diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveRole.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveRole.java index f0219040c47bc09fe2052d8e95a3ea83637e6aae..95dfd2cfeecceb6d3751cba876484c7f5d7a66f9 100644 --- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveRole.java +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLRetrieveRole.java @@ -25,10 +25,14 @@ package org.caosdb.server.database.backend.implementation.MySQL; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.LinkedList; +import java.util.Map; import org.caosdb.server.accessControl.Role; import org.caosdb.server.database.access.Access; import org.caosdb.server.database.backend.interfaces.RetrieveRoleImpl; import org.caosdb.server.database.exceptions.TransactionException; +import org.caosdb.server.permissions.PermissionRule; +import org.eclipse.jetty.util.ajax.JSON; public class MySQLRetrieveRole extends MySQLTransaction implements RetrieveRoleImpl { @@ -36,7 +40,8 @@ public class MySQLRetrieveRole extends MySQLTransaction implements RetrieveRoleI super(access); } - public static final String STMT_RETRIEVE_ROLE = "SELECT description FROM roles WHERE name=?"; + public static final String STMT_RETRIEVE_ROLE = + "SELECT r.description AS description, p.permissions AS permissions FROM roles AS r LEFT JOIN permissions AS p ON (r.name = p.role) WHERE r.name=?"; @Override public Role retrieve(final String role) throws TransactionException { @@ -49,6 +54,7 @@ public class MySQLRetrieveRole extends MySQLTransaction implements RetrieveRoleI final Role ret = new Role(); ret.name = role; ret.description = rs.getString("description"); + ret.permission_rules = parse(rs.getString("permissions")); return ret; } else { return null; @@ -62,4 +68,16 @@ public class MySQLRetrieveRole extends MySQLTransaction implements RetrieveRoleI throw new TransactionException(e); } } + + @SuppressWarnings("unchecked") + private LinkedList<PermissionRule> parse(String string) { + if (string == null) return null; + final Object[] maps = (Object[]) JSON.parse(string); + final LinkedList<PermissionRule> ret = new LinkedList<>(); + for (final Object map : maps) { + ret.add(PermissionRule.parse((Map<String, String>) map)); + } + + return ret; + } } diff --git a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLUpdateUserRoles.java b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLUpdateUserRoles.java index 62cb68bf58fc8269cc365fa167929ff79726499b..2e41e24ab0e9457d0dca8bea31ae9379b2e62f5b 100644 --- a/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLUpdateUserRoles.java +++ b/src/main/java/org/caosdb/server/database/backend/implementation/MySQL/MySQLUpdateUserRoles.java @@ -24,7 +24,7 @@ package org.caosdb.server.database.backend.implementation.MySQL; import java.sql.PreparedStatement; import java.sql.SQLException; -import java.util.HashSet; +import java.util.Set; import org.caosdb.server.database.access.Access; import org.caosdb.server.database.backend.interfaces.UpdateUserRolesImpl; import org.caosdb.server.database.exceptions.TransactionException; @@ -41,7 +41,7 @@ public class MySQLUpdateUserRoles extends MySQLTransaction implements UpdateUser "INSERT INTO user_roles (realm, user, role) VALUES (?,?,?);"; @Override - public void updateUserRoles(final String realm, final String user, final HashSet<String> roles) + public void updateUserRoles(final String realm, final String user, final Set<String> roles) throws TransactionException { try { final PreparedStatement delete_stmt = prepareStatement(STMT_DELETE_USER_ROLES); diff --git a/src/main/java/org/caosdb/server/database/backend/interfaces/LogUserVisitImpl.java b/src/main/java/org/caosdb/server/database/backend/interfaces/LogUserVisitImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..6c0f3cb504b8d985c717974be700e3062242d62d --- /dev/null +++ b/src/main/java/org/caosdb/server/database/backend/interfaces/LogUserVisitImpl.java @@ -0,0 +1,25 @@ +/* + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package org.caosdb.server.database.backend.interfaces; + +public interface LogUserVisitImpl extends BackendTransactionImpl { + + void log(long timestamp, String realm, String username, String type); +} diff --git a/src/main/java/org/caosdb/server/database/backend/interfaces/UpdateUserRolesImpl.java b/src/main/java/org/caosdb/server/database/backend/interfaces/UpdateUserRolesImpl.java index f2abfbe3cb7846f16e21d8f9a719ad708884841c..891df301e992f42c38f7c52d867353a65cddd1b2 100644 --- a/src/main/java/org/caosdb/server/database/backend/interfaces/UpdateUserRolesImpl.java +++ b/src/main/java/org/caosdb/server/database/backend/interfaces/UpdateUserRolesImpl.java @@ -22,11 +22,11 @@ */ package org.caosdb.server.database.backend.interfaces; -import java.util.HashSet; +import java.util.Set; import org.caosdb.server.database.exceptions.TransactionException; public interface UpdateUserRolesImpl extends BackendTransactionImpl { - public void updateUserRoles(String realm, String user, HashSet<String> roles) + public void updateUserRoles(String realm, String user, Set<String> roles) throws TransactionException; } diff --git a/src/main/java/org/caosdb/server/database/backend/transaction/LogUserVisit.java b/src/main/java/org/caosdb/server/database/backend/transaction/LogUserVisit.java new file mode 100644 index 0000000000000000000000000000000000000000..c5d107c2936d467be775175cac5f6b81e3cbce70 --- /dev/null +++ b/src/main/java/org/caosdb/server/database/backend/transaction/LogUserVisit.java @@ -0,0 +1,47 @@ +/* + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * ** end header + */ +package org.caosdb.server.database.backend.transaction; + +import org.caosdb.server.database.BackendTransaction; +import org.caosdb.server.database.backend.interfaces.LogUserVisitImpl; +import org.caosdb.server.database.exceptions.TransactionException; + +public class LogUserVisit extends BackendTransaction { + + private String realm; + private String username; + private String type; + private long timestamp; + + public LogUserVisit(long timestamp, String realm, String username, String type) { + this.timestamp = timestamp; + this.realm = realm; + this.username = username; + this.type = type; + } + + @Override + protected void execute() throws TransactionException { + final LogUserVisitImpl t = getImplementation(LogUserVisitImpl.class); + t.log(timestamp, realm, username, type); + } +} diff --git a/src/main/java/org/caosdb/server/database/backend/transaction/UpdateUserRoles.java b/src/main/java/org/caosdb/server/database/backend/transaction/UpdateUserRoles.java index 66b3cb8e6f03c3abde0ccaa051a1228057d973f7..13b4906e48cd5c7a93e03683d4b57b7381d14f16 100644 --- a/src/main/java/org/caosdb/server/database/backend/transaction/UpdateUserRoles.java +++ b/src/main/java/org/caosdb/server/database/backend/transaction/UpdateUserRoles.java @@ -22,7 +22,7 @@ */ package org.caosdb.server.database.backend.transaction; -import java.util.HashSet; +import java.util.Set; import org.caosdb.server.accessControl.Principal; import org.caosdb.server.database.BackendTransaction; import org.caosdb.server.database.backend.interfaces.UpdateUserRolesImpl; @@ -31,10 +31,10 @@ import org.caosdb.server.database.exceptions.TransactionException; public class UpdateUserRoles extends BackendTransaction { private final String user; - private final HashSet<String> roles; + private final Set<String> roles; private final String realm; - public UpdateUserRoles(final String realm, final String user, final HashSet<String> roles) { + public UpdateUserRoles(final String realm, final String user, final Set<String> roles) { this.realm = realm; this.user = user; this.roles = roles; diff --git a/src/main/java/org/caosdb/server/grpc/AccessControlManagementServiceImpl.java b/src/main/java/org/caosdb/server/grpc/AccessControlManagementServiceImpl.java index 258cb8ada62ffdb5dd01beae1ceff8639fb6a988..182d5cb5dd194db4475f3a923a9bf207eb7ab498 100644 --- a/src/main/java/org/caosdb/server/grpc/AccessControlManagementServiceImpl.java +++ b/src/main/java/org/caosdb/server/grpc/AccessControlManagementServiceImpl.java @@ -1,6 +1,8 @@ package org.caosdb.server.grpc; import io.grpc.stub.StreamObserver; +import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import org.caosdb.api.acm.v1alpha1.AccessControlManagementServiceGrpc.AccessControlManagementServiceImplBase; import org.caosdb.api.acm.v1alpha1.CreateSingleRoleRequest; @@ -11,6 +13,11 @@ import org.caosdb.api.acm.v1alpha1.ListRolesRequest; import org.caosdb.api.acm.v1alpha1.ListRolesResponse; import org.caosdb.api.acm.v1alpha1.ListUsersRequest; import org.caosdb.api.acm.v1alpha1.ListUsersResponse; +import org.caosdb.api.acm.v1alpha1.PermissionRule; +import org.caosdb.api.acm.v1alpha1.RetrieveSingleRoleRequest; +import org.caosdb.api.acm.v1alpha1.RetrieveSingleRoleResponse; +import org.caosdb.api.acm.v1alpha1.RetrieveSingleUserRequest; +import org.caosdb.api.acm.v1alpha1.RetrieveSingleUserResponse; import org.caosdb.api.acm.v1alpha1.User; import org.caosdb.api.acm.v1alpha1.UserStatus; import org.caosdb.server.accessControl.Role; @@ -19,6 +26,8 @@ import org.caosdb.server.transaction.InsertRoleTransaction; import org.caosdb.server.transaction.InsertUserTransaction; import org.caosdb.server.transaction.ListRolesTransaction; import org.caosdb.server.transaction.ListUsersTransaction; +import org.caosdb.server.transaction.RetrieveRoleTransaction; +import org.caosdb.server.transaction.RetrieveUserTransaction; public class AccessControlManagementServiceImpl extends AccessControlManagementServiceImplBase { @@ -29,13 +38,26 @@ public class AccessControlManagementServiceImpl extends AccessControlManagementS result.realm = user.getRealm(); result.name = user.getName(); result.email = user.getEmail(); - result.status = - (user.getStatus() == UserStatus.USER_STATUS_ACTIVE - ? org.caosdb.server.accessControl.UserStatus.ACTIVE - : org.caosdb.server.accessControl.UserStatus.INACTIVE); + result.status = convert(user.getStatus()); + if (user.getRolesCount() >= 0) { + result.roles = new HashSet<String>(); + user.getRolesList().forEach(result.roles::add); + } return result; } + private org.caosdb.server.accessControl.UserStatus convert(UserStatus status) { + switch (status) { + case USER_STATUS_ACTIVE: + return org.caosdb.server.accessControl.UserStatus.ACTIVE; + case USER_STATUS_INACTIVE: + return org.caosdb.server.accessControl.UserStatus.INACTIVE; + default: + break; + } + return org.caosdb.server.accessControl.UserStatus.INACTIVE; + } + private ListUsersResponse convertUsers(List<ProtoUser> users) { ListUsersResponse.Builder response = ListUsersResponse.newBuilder(); users.forEach( @@ -57,11 +79,21 @@ public class AccessControlManagementServiceImpl extends AccessControlManagementS if (user.entity != null) { result.setEntityId(Integer.toString(user.entity)); } + if (user.roles != null) { + result.addAllRoles(user.roles); + } return result; } private UserStatus convert(org.caosdb.server.accessControl.UserStatus status) { - return UserStatus.valueOf(status.toString()); + switch (status) { + case ACTIVE: + return UserStatus.USER_STATUS_ACTIVE; + case INACTIVE: + return UserStatus.USER_STATUS_INACTIVE; + default: + return UserStatus.USER_STATUS_UNSPECIFIED; + } } private Role convert(org.caosdb.api.acm.v1alpha1.Role role) { @@ -86,7 +118,26 @@ public class AccessControlManagementServiceImpl extends AccessControlManagementS org.caosdb.api.acm.v1alpha1.Role.Builder result = org.caosdb.api.acm.v1alpha1.Role.newBuilder(); result.setDescription(role.description); result.setName(role.name); + if (role.permission_rules != null) result.addAllPermissionRules(convert(role.permission_rules)); + return result; + } + + private PermissionRule convert(org.caosdb.server.permissions.PermissionRule rule) { + PermissionRule.Builder result = PermissionRule.newBuilder(); + result.setGrant(rule.isGrant()); + result.setPriority(rule.isPriority()); + result.setPermission(rule.getPermission()); + return result.build(); + } + + private Iterable<PermissionRule> convert( + LinkedList<org.caosdb.server.permissions.PermissionRule> permission_rules) { + List<PermissionRule> result = new LinkedList<>(); + permission_rules.forEach( + (rule) -> { + result.add(convert(rule)); + }); return result; } @@ -111,6 +162,14 @@ public class AccessControlManagementServiceImpl extends AccessControlManagementS return CreateSingleRoleResponse.newBuilder().build(); } + private RetrieveSingleRoleResponse retrieveSingleRoleTransaction( + RetrieveSingleRoleRequest request) throws Exception { + RetrieveRoleTransaction transaction = new RetrieveRoleTransaction(request.getName()); + transaction.execute(); + + return RetrieveSingleRoleResponse.newBuilder().setRole(convert(transaction.getRole())).build(); + } + ////////////////// ... for users private ListUsersResponse listUsersTransaction(ListUsersRequest request) throws Exception { @@ -123,13 +182,21 @@ public class AccessControlManagementServiceImpl extends AccessControlManagementS private CreateSingleUserResponse createSingleUserTransaction(CreateSingleUserRequest request) throws Exception { ProtoUser user = convert(request.getUser()); - InsertUserTransaction transaction = - new InsertUserTransaction(user, request.getUser().getPassword()); + InsertUserTransaction transaction = new InsertUserTransaction(user, request.getPassword()); transaction.execute(); return CreateSingleUserResponse.newBuilder().build(); } + private RetrieveSingleUserResponse retrieveSingleUserTransaction( + RetrieveSingleUserRequest request) throws Exception { + RetrieveUserTransaction transaction = + new RetrieveUserTransaction(request.getRealm(), request.getName()); + transaction.execute(); + + return RetrieveSingleUserResponse.newBuilder().setUser(convert(transaction.getUser())).build(); + } + ///////////////////////////////////// RPC Methods (API) @Override @@ -174,6 +241,21 @@ public class AccessControlManagementServiceImpl extends AccessControlManagementS } } + @Override + public void retrieveSingleRole( + RetrieveSingleRoleRequest request, + StreamObserver<RetrieveSingleRoleResponse> responseObserver) { + try { + final RetrieveSingleRoleResponse response = retrieveSingleRoleTransaction(request); + responseObserver.onNext(response); + responseObserver.onCompleted(); + + } catch (final Exception e) { + e.printStackTrace(); + responseObserver.onError(e); + } + } + @Override public void createSingleUser( CreateSingleUserRequest request, StreamObserver<CreateSingleUserResponse> responseObserver) { @@ -187,4 +269,19 @@ public class AccessControlManagementServiceImpl extends AccessControlManagementS responseObserver.onError(e); } } + + @Override + public void retrieveSingleUser( + RetrieveSingleUserRequest request, + StreamObserver<RetrieveSingleUserResponse> responseObserver) { + try { + final RetrieveSingleUserResponse response = retrieveSingleUserTransaction(request); + responseObserver.onNext(response); + responseObserver.onCompleted(); + + } catch (final Exception e) { + e.printStackTrace(); + responseObserver.onError(e); + } + } } diff --git a/src/main/java/org/caosdb/server/permissions/PermissionRule.java b/src/main/java/org/caosdb/server/permissions/PermissionRule.java index 85d3b62834a67a4fc46ea9b3c38d19e4b8261d74..7a8d4e26dc4cb0c4e4b8a7e2eea1de8a2bee2a7e 100644 --- a/src/main/java/org/caosdb/server/permissions/PermissionRule.java +++ b/src/main/java/org/caosdb/server/permissions/PermissionRule.java @@ -54,6 +54,10 @@ public class PermissionRule { return this.priority; } + public String getPermission() { + return permission; + } + public Permission getPermission(String realm, String username) { return new WildcardPermission( permission.replaceAll("\\?REALM\\?", realm).replaceAll("\\?USERNAME\\?", username)); diff --git a/src/main/java/org/caosdb/server/transaction/InsertUserTransaction.java b/src/main/java/org/caosdb/server/transaction/InsertUserTransaction.java index d63cd60fc94e09bb0230551bf9fd432b9bee82bf..235598b9f522d4aa04af2d899847392d82994702 100644 --- a/src/main/java/org/caosdb/server/transaction/InsertUserTransaction.java +++ b/src/main/java/org/caosdb/server/transaction/InsertUserTransaction.java @@ -29,6 +29,7 @@ import org.caosdb.server.accessControl.UserStatus; import org.caosdb.server.database.backend.transaction.RetrievePasswordValidator; import org.caosdb.server.database.backend.transaction.SetPassword; import org.caosdb.server.database.backend.transaction.UpdateUser; +import org.caosdb.server.database.backend.transaction.UpdateUserRoles; import org.caosdb.server.database.proto.ProtoUser; import org.caosdb.server.utils.ServerMessages; import org.caosdb.server.utils.Utils; @@ -79,6 +80,7 @@ public class InsertUserTransaction extends AccessControlTransaction { execute(new SetPassword(this.user.name, this.password), getAccess()); execute(new UpdateUser(this.user), getAccess()); + execute(new UpdateUserRoles(this.user.realm, this.user.name, this.user.roles), getAccess()); } else { throw ServerMessages.ACCOUNT_NAME_NOT_UNIQUE; } diff --git a/src/main/java/org/caosdb/server/transaction/LogUserVisitTransaction.java b/src/main/java/org/caosdb/server/transaction/LogUserVisitTransaction.java new file mode 100644 index 0000000000000000000000000000000000000000..dff0d34fed5bab445bfd761817aecc474def6025 --- /dev/null +++ b/src/main/java/org/caosdb/server/transaction/LogUserVisitTransaction.java @@ -0,0 +1,42 @@ +/* + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ +package org.caosdb.server.transaction; + +import org.caosdb.server.database.backend.transaction.LogUserVisit; + +public class LogUserVisitTransaction extends AccessControlTransaction { + + private String realm; + private String username; + private String type; + private long timestamp; + + public LogUserVisitTransaction(long timestamp, String realm, String username, String type) { + this.timestamp = timestamp; + this.realm = realm; + this.username = username; + this.type = type; + } + + @Override + protected void transaction() throws Exception { + execute(new LogUserVisit(timestamp, realm, username, type), getAccess()); + } +} diff --git a/src/main/java/org/caosdb/server/transaction/RetrieveUserTransaction.java b/src/main/java/org/caosdb/server/transaction/RetrieveUserTransaction.java index 228b1585233ae71d3b7130196f68c3b9f83f5ed2..f66cbe695013b539093eeb81ef85f52b04fd08bd 100644 --- a/src/main/java/org/caosdb/server/transaction/RetrieveUserTransaction.java +++ b/src/main/java/org/caosdb/server/transaction/RetrieveUserTransaction.java @@ -89,4 +89,8 @@ public class RetrieveUserTransaction extends AccessControlTransaction { public boolean isActive() { return this.user.status == UserStatus.ACTIVE; } + + public ProtoUser getUser() { + return user; + } } diff --git a/src/test/java/org/caosdb/server/authentication/AuthTokenTest.java b/src/test/java/org/caosdb/server/authentication/AuthTokenTest.java index 6ec17c6812f62c4ea5205b8efea488f804d8d0db..0aa2781f26c17788604c10aa4fbe48fbd08076c2 100644 --- a/src/test/java/org/caosdb/server/authentication/AuthTokenTest.java +++ b/src/test/java/org/caosdb/server/authentication/AuthTokenTest.java @@ -57,7 +57,7 @@ import org.caosdb.server.database.backend.interfaces.RetrieveUserImpl; import org.caosdb.server.grpc.AuthInterceptor; import org.caosdb.server.resource.TestScriptingResource.RetrievePasswordValidator; import org.caosdb.server.resource.TestScriptingResource.RetrievePermissionRules; -import org.caosdb.server.resource.TestScriptingResource.RetrieveRole; +import org.caosdb.server.resource.TestScriptingResource.RetrieveRoleMockup; import org.caosdb.server.resource.TestScriptingResource.RetrieveUser; import org.junit.Assert; import org.junit.Before; @@ -73,7 +73,7 @@ public class AuthTokenTest { @BeforeClass public static void setupShiro() throws IOException { - BackendTransaction.setImpl(RetrieveRoleImpl.class, RetrieveRole.class); + BackendTransaction.setImpl(RetrieveRoleImpl.class, RetrieveRoleMockup.class); BackendTransaction.setImpl(RetrievePermissionRulesImpl.class, RetrievePermissionRules.class); BackendTransaction.setImpl(RetrieveUserImpl.class, RetrieveUser.class); BackendTransaction.setImpl( diff --git a/src/test/java/org/caosdb/server/resource/TestScriptingResource.java b/src/test/java/org/caosdb/server/resource/TestScriptingResource.java index 7f7434528678dbd2e1886fade2116d0c9f766740..abb5e8023ade1dcd3364b2d7ea4ef7805732444e 100644 --- a/src/test/java/org/caosdb/server/resource/TestScriptingResource.java +++ b/src/test/java/org/caosdb/server/resource/TestScriptingResource.java @@ -64,9 +64,9 @@ import org.restlet.representation.StringRepresentation; public class TestScriptingResource { - public static class RetrieveRole implements RetrieveRoleImpl { + public static class RetrieveRoleMockup implements RetrieveRoleImpl { - public RetrieveRole(Access a) {} + public RetrieveRoleMockup(Access a) {} @Override public Role retrieve(String role) throws TransactionException { @@ -154,7 +154,7 @@ public class TestScriptingResource { CaosDBServer.initServerProperties(); CaosDBServer.initShiro(); - BackendTransaction.setImpl(RetrieveRoleImpl.class, RetrieveRole.class); + BackendTransaction.setImpl(RetrieveRoleImpl.class, RetrieveRoleMockup.class); BackendTransaction.setImpl(RetrievePermissionRulesImpl.class, RetrievePermissionRules.class); BackendTransaction.setImpl(RetrieveUserImpl.class, RetrieveUser.class); BackendTransaction.setImpl(