Skip to content
Snippets Groups Projects
Verified Commit 009a9361 authored by Timm Fitschen's avatar Timm Fitschen
Browse files

WIP: grpc acm

parent 1d6c072d
No related branches found
No related tags found
2 merge requests!58REL: prepare release 0.7.2,!45F grpc f acm
......@@ -38,6 +38,7 @@
<grpc.version>1.42.1</grpc.version>
<netty-tcnative.version>2.0.34.Final</netty-tcnative.version>
<restlet.version>2.4.3</restlet.version>
<log4j.version>2.15.0</log4j.version>
</properties>
<repositories>
<repository>
......@@ -167,22 +168,22 @@
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.11.1</version>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
<version>1.7.32</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.1</version>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.1</version>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
......
......@@ -592,7 +592,7 @@ public class AccessControlManagementServiceImpl extends AccessControlManagementS
Subject subject = SecurityUtils.getSubject();
if (AuthenticationUtils.isAnonymous(subject)) {
responseObserver.onError(
new StatusException(Status.UNAUTHENTICATED.withDescription("Please login!")));
new StatusException(AuthInterceptor.PLEASE_LOG_IN));
return;
} else {
responseObserver.onError(
......
......@@ -60,6 +60,7 @@ import org.restlet.data.CookieSetting;
*/
public class AuthInterceptor implements ServerInterceptor {
public static final Status PLEASE_LOG_IN = Status.UNAUTHENTICATED.withDescription("Please log in!");
public static final Key<String> AUTHENTICATION_HEADER =
Key.of("authentication", Metadata.ASCII_STRING_MARSHALLER);
public static final Key<String> AUTHORIZATION_HEADER =
......@@ -109,7 +110,7 @@ public class AuthInterceptor implements ServerInterceptor {
final String username = split[0];
final String password = split[1];
final RealmUsernamePasswordToken token =
new RealmUsernamePasswordToken(UserSources.getDefaultRealm(), username, password);
new RealmUsernamePasswordToken(UserSources.guessRealm(username, UserSources.getDefaultRealm()), username, password);
final Subject subject = SecurityUtils.getSubject();
subject.login(token);
return subject;
......@@ -143,7 +144,7 @@ public class AuthInterceptor implements ServerInterceptor {
if (authentication == null && isAuthOptional()) {
return anonymous(call, headers, next);
} else if (authentication == null) {
status = Status.UNAUTHENTICATED.withDescription("Please login.");
status = PLEASE_LOG_IN;
} else if (authentication.startsWith(BASIC_SCHEME_PREFIX)) {
return basicAuth(authentication.substring(BASIC_SCHEME_PREFIX.length()), call, headers, next);
} else if (SESSION_TOKEN_COOKIE_PREFIX_PREDICATE.test(authentication)) {
......@@ -255,8 +256,7 @@ public class AuthInterceptor implements ServerInterceptor {
final Metadata headers,
final ServerCallHandler<ReqT, RespT> next,
final String tag) {
final Context context = Context.current();
context.withValue(SUBJECT_KEY, subject);
final Context context = Context.current().withValue(SUBJECT_KEY, subject);
ServerCall<ReqT, RespT> cookieSetter = new CookieSetter<>(call, subject, tag);
return Contexts.interceptCall(context, cookieSetter, headers, next);
}
......
......@@ -20,10 +20,10 @@
package org.caosdb.server.grpc;
import io.grpc.Context;
import io.grpc.stub.StreamObserver;
import java.util.Collection;
import java.util.LinkedList;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.Permission;
import org.apache.shiro.subject.Subject;
......@@ -77,6 +77,7 @@ public class GeneralInfoServiceImpl extends GeneralInfoServiceImplBase {
final StreamObserver<GetVersionInfoResponse> responseObserver) {
try {
AuthInterceptor.bindSubject();
GetVersionInfoResponse response = getVersionInfo(request);
responseObserver.onNext(response);
responseObserver.onCompleted();
......@@ -87,68 +88,40 @@ public class GeneralInfoServiceImpl extends GeneralInfoServiceImplBase {
}
private GetSessionInfoResponse getSessionInfo(GetSessionInfoRequest request) {
Subject subject = AuthInterceptor.bindSubject();
System.out.println(
"getSessionInfo (in): "
+ Long.toString(Thread.currentThread().getId())
+ " "
+ Thread.currentThread().getName()
+ " subject: "
+ subject.toString());
Subject subject = SecurityUtils.getSubject();
GetSessionInfoResponse.Builder response = GetSessionInfoResponse.newBuilder();
Principal principal = (Principal) subject.getPrincipal();
try {
response.setUsername(principal.getUsername());
response.setRealm(principal.getRealm());
response.setUsername(principal.getUsername());
response.setRealm(principal.getRealm());
AuthorizationInfo authorizationInfo = AuthenticationUtils.getAuthorizationInfo(subject);
Collection<String> roles = authorizationInfo.getRoles();
if (roles != null && !roles.isEmpty()) {
response.addAllRoles(roles);
}
Collection<String> permissions = new LinkedList<>();
AuthorizationInfo authorizationInfo = AuthenticationUtils.getAuthorizationInfo(subject);
Collection<String> roles = authorizationInfo.getRoles();
if (roles != null && !roles.isEmpty()) {
response.addAllRoles(roles);
}
Collection<String> stringPermissions = authorizationInfo.getStringPermissions();
if (stringPermissions != null && !stringPermissions.isEmpty()) {
permissions.addAll(stringPermissions);
}
Collection<String> permissions = new LinkedList<>();
for (Permission p : authorizationInfo.getObjectPermissions()) {
if (p instanceof CaosPermission) {
permissions.addAll(((CaosPermission) p).getStringPermissions(subject));
} else {
permissions.add(p.toString());
}
}
Collection<String> stringPermissions = authorizationInfo.getStringPermissions();
if (stringPermissions != null && !stringPermissions.isEmpty()) {
permissions.addAll(stringPermissions);
}
if (permissions != null && !permissions.isEmpty()) {
response.addAllPermissions(permissions);
for (Permission p : authorizationInfo.getObjectPermissions()) {
if (p instanceof CaosPermission) {
permissions.addAll(((CaosPermission) p).getStringPermissions(subject));
} else {
permissions.add(p.toString());
}
}
System.out.println(
"getSessionInfo (out): "
+ Long.toString(Thread.currentThread().getId())
+ " "
+ Thread.currentThread().getName()
+ " subject: "
+ subject.toString());
return response.build();
} catch (NullPointerException e) {
final Context context = Context.current();
System.out.println(
"getSessionInfo (exc): "
+ Long.toString(Thread.currentThread().getId())
+ " "
+ Thread.currentThread().getName()
+ " subject: "
+ subject.toString());
throw e;
if (permissions != null && !permissions.isEmpty()) {
response.addAllPermissions(permissions);
}
return response.build();
}
@Override
......@@ -156,6 +129,7 @@ public class GeneralInfoServiceImpl extends GeneralInfoServiceImplBase {
GetSessionInfoRequest request, StreamObserver<GetSessionInfoResponse> responseObserver) {
try {
AuthInterceptor.bindSubject();
final GetSessionInfoResponse response = getSessionInfo(request);
responseObserver.onNext(response);
responseObserver.onCompleted();
......
......@@ -25,13 +25,14 @@ package org.caosdb.server.transaction;
import org.apache.shiro.SecurityUtils;
import org.caosdb.server.accessControl.ACMPermissions;
import org.caosdb.server.accessControl.Principal;
import org.caosdb.server.accessControl.UserSources;
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.entity.Message;
import org.caosdb.server.utils.ServerMessages;
import org.caosdb.server.utils.Utils;
import org.jdom2.Element;
......@@ -65,6 +66,8 @@ public class InsertUserTransaction extends AccessControlTransaction {
SecurityUtils.getSubject()
.checkPermission(ACMPermissions.PERMISSION_INSERT_USER(this.user.realm));
checkUserName(this.user.name);
if (this.user.email != null && !Utils.isRFC822Compliant(this.user.email)) {
throw ServerMessages.EMAIL_NOT_WELL_FORMED;
}
......@@ -73,16 +76,31 @@ public class InsertUserTransaction extends AccessControlTransaction {
UpdateUserTransaction.checkEntityExists(this.user.entity);
}
if (execute(new RetrievePasswordValidator(this.user.name), getAccess()).getValidator()
== null) {
if (this.password != null) {
Utils.checkPasswordStrength(this.password);
}
if (this.password != null) {
Utils.checkPasswordStrength(this.password);
}
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());
}
/*
* Names should have at least a length of 1, a maximum length of 32 and match
* ^[a-zA-Z_][a-zA-Z0-9_-]*$.
*/
private void checkUserName(String name) throws Message {
// Make this configurable?
final boolean length = name.length() >= 1 && name.length() <= 32;
final boolean match =
name.matches("^[\\p{Lower}\\p{Upper}_][\\p{Lower}\\p{Upper}\\p{Digit}_-]*$");
if (!(length && match)) {
throw ServerMessages.INVALID_USER_NAME(
"User names must have a length from 1 to 32 characters, begin with a latin letter a-z (upper case or lower case) or an underscore (_), and all other characters must be latin letters, arabic numbers, hyphens (-) or undescores (_).");
}
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 {
if (UserSources.isUserExisting(new Principal(this.user.realm, this.user.name))) {
throw ServerMessages.ACCOUNT_NAME_NOT_UNIQUE;
}
}
......
......@@ -597,4 +597,11 @@ public class ServerMessages {
MessageType.Error,
MessageCode.MESSAGE_CODE_INTEGRITY_VIOLATION,
"This entity caused an unexpected integrity violation. This is a strong indicator for a server bug. Please report.");
public static final Message INVALID_USER_NAME(String policy) {
return new Message(
MessageType.Error,
MessageCode.MESSAGE_CODE_UNKNOWN,
"The user name does not comply with the policies for user names: " + policy);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment