diff --git a/self-services/pom.xml b/self-services/pom.xml
index c7a5d53..432eb3d 100644
--- a/self-services/pom.xml
+++ b/self-services/pom.xml
@@ -38,6 +38,17 @@
protobuf-java
provided
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
diff --git a/self-services/src/main/java/jp/openstandia/midpoint/grpc/SelfServiceResource.java b/self-services/src/main/java/jp/openstandia/midpoint/grpc/SelfServiceResource.java
index d081690..adf27bc 100644
--- a/self-services/src/main/java/jp/openstandia/midpoint/grpc/SelfServiceResource.java
+++ b/self-services/src/main/java/jp/openstandia/midpoint/grpc/SelfServiceResource.java
@@ -17,6 +17,7 @@
import com.evolveum.midpoint.prism.delta.builder.S_ItemEntry;
import com.evolveum.midpoint.prism.delta.builder.S_MaybeDelete;
import com.evolveum.midpoint.prism.delta.builder.S_ValuesEntry;
+import com.evolveum.midpoint.prism.path.ItemName;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.polystring.PolyString;
import com.evolveum.midpoint.prism.query.ObjectQuery;
@@ -24,6 +25,9 @@
import com.evolveum.midpoint.schema.SchemaConstantsGenerated;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.task.api.Task;
+import com.evolveum.midpoint.util.LocalizableMessage;
+import com.evolveum.midpoint.util.LocalizableMessageList;
+import com.evolveum.midpoint.util.SingleLocalizableMessage;
import com.evolveum.midpoint.util.exception.*;
import com.evolveum.midpoint.util.logging.LoggingUtils;
import com.evolveum.midpoint.util.logging.Trace;
@@ -33,8 +37,10 @@
import com.evolveum.midpoint.xml.ns._public.common.common_3.PasswordType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;
import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType;
+import io.grpc.Metadata;
import io.grpc.Status;
import io.grpc.StatusRuntimeException;
+import io.grpc.protobuf.ProtoUtils;
import io.grpc.stub.StreamObserver;
import org.lognet.springboot.grpc.GRpcService;
import org.springframework.beans.factory.annotation.Autowired;
@@ -72,6 +78,18 @@ public class SelfServiceResource extends SelfServiceResourceGrpc.SelfServiceReso
@Autowired
protected transient AuthenticationEvaluator passwordAuthenticationEvaluator;
+ @Override
+ public Metadata handlePolicyViolationException(PolicyViolationException e) {
+ PolicyError error = TypeConverter.toPolicyError(e);
+ Metadata metadata = new Metadata();
+
+ Metadata.Key POLICY_ERROR_KEY =
+ ProtoUtils.keyForProto(PolicyError.getDefaultInstance());
+ metadata.put(POLICY_ERROR_KEY, error);
+
+ return metadata;
+ }
+
@Override
public void modifyProfile(ModifyProfileRequest request, StreamObserver responseObserver) {
LOGGER.debug("Start modifyProfile");
@@ -89,41 +107,24 @@ public void modifyProfile(ModifyProfileRequest request, StreamObserver responseObserver) {
LOGGER.debug("Start updateCredential");
@@ -205,7 +203,6 @@ public void forceUpdateCredential(ForceUpdateCredentialRequest request, StreamOb
public void requestRole(RequestRoleRequest request, StreamObserver responseObserver) {
LOGGER.debug("Start requestRole");
-
LOGGER.debug("End requestRole");
}
@@ -256,7 +253,10 @@ protected void updateCredential(MidPointTaskContext ctx, String oldCred, String
modelService.executeChanges(deltas, null, task, updateResult);
updateResult.computeStatus();
- } catch (EncryptionException | ObjectAlreadyExistsException | PolicyViolationException e) {
+ } catch (PolicyViolationException e) {
+ LoggingUtils.logExceptionAsWarning(LOGGER, "Couldn't save password changes because of policy violation: {}", e, e.getMessage());
+ throw e;
+ } catch (EncryptionException | ObjectAlreadyExistsException e) {
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't save password changes", e);
throw e;
} finally {
diff --git a/self-services/src/main/java/jp/openstandia/midpoint/grpc/TypeConverter.java b/self-services/src/main/java/jp/openstandia/midpoint/grpc/TypeConverter.java
new file mode 100644
index 0000000..d7c5d31
--- /dev/null
+++ b/self-services/src/main/java/jp/openstandia/midpoint/grpc/TypeConverter.java
@@ -0,0 +1,172 @@
+package jp.openstandia.midpoint.grpc;
+
+import com.evolveum.midpoint.prism.path.ItemName;
+import com.evolveum.midpoint.prism.polystring.PolyString;
+import com.evolveum.midpoint.util.LocalizableMessage;
+import com.evolveum.midpoint.util.LocalizableMessageList;
+import com.evolveum.midpoint.util.SingleLocalizableMessage;
+import com.evolveum.midpoint.util.exception.PolicyViolationException;
+import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;
+import com.evolveum.prism.xml.ns._public.types_3.PolyStringType;
+
+import javax.xml.bind.annotation.XmlElement;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class TypeConverter {
+
+ private static Map userTypeMap = new HashMap<>();
+ private static Map userValueTypeMap = new HashMap<>();
+
+ static {
+ Map strToItemName = new HashMap<>();
+
+ Field[] fields = UserType.class.getFields();
+ Arrays.stream(fields)
+ .filter(x -> x.getName().startsWith("F_") && x.getType() == ItemName.class)
+ .forEach(x -> {
+ String name = x.getName();
+ try {
+ UserItemPath path = UserItemPath.valueOf(name);
+ ItemName itemName = (ItemName) x.get(null);
+ userTypeMap.put(path, itemName);
+ strToItemName.put(itemName.getLocalPart(), itemName);
+ } catch (IllegalArgumentException | IllegalAccessException ignore) {
+ }
+ });
+
+ Method[] methods = UserType.class.getMethods();
+ Arrays.stream(methods)
+ .filter(x -> x.isAnnotationPresent(XmlElement.class))
+ .forEach(x -> {
+ XmlElement ele = x.getAnnotation(XmlElement.class);
+
+ ItemName itemName = strToItemName.get(ele.name());
+ if (itemName == null) {
+ return;
+ }
+ Class> returnType = x.getReturnType();
+
+ if (returnType.isAssignableFrom(List.class)) {
+ Type genericReturnType = x.getGenericReturnType();
+ String typeName = genericReturnType.getTypeName();
+ if (typeName.contains(String.class.getName())) {
+ userValueTypeMap.put(itemName, String.class);
+ } else if (typeName.contains(PolyStringType.class.getName())) {
+ userValueTypeMap.put(itemName, PolyStringType.class);
+ } else {
+ throw new UnsupportedOperationException(itemName + " is not supported");
+ }
+ } else {
+ userValueTypeMap.put(itemName, returnType);
+ }
+ });
+ }
+
+ public static ItemName toItemName(UserItemPath path) {
+ ItemName itemName = userTypeMap.get(path);
+ if (itemName == null) {
+ throw new UnsupportedOperationException(path + " is not supported");
+ }
+ return itemName;
+ }
+
+ public static Object toValue(UserItemPath path, String value) {
+ ItemName itemName = toItemName(path);
+
+ Class clazz = userValueTypeMap.get(itemName);
+
+ if (clazz.isAssignableFrom(String.class)) {
+ return value;
+ }
+ if (clazz.isAssignableFrom(PolyStringType.class)) {
+ return PolyString.fromOrig((String) value);
+ }
+
+ throw new UnsupportedOperationException(path + " is not supported");
+ }
+
+ public static PolicyError toPolicyError(PolicyViolationException e) {
+ PolicyError.Builder builder = PolicyError.newBuilder();
+ MessageWrapper wrapper = null;
+
+ LocalizableMessage msg = e.getUserFriendlyMessage();
+ if (msg instanceof SingleLocalizableMessage) {
+ wrapper = toMessageWrapper((SingleLocalizableMessage) msg);
+
+ } else if (msg instanceof LocalizableMessageList) {
+ wrapper = toMessageWrapper((LocalizableMessageList) msg);
+ }
+
+ if (wrapper == null) {
+ throw new UnsupportedOperationException(msg.getClass() + " is not supported");
+ }
+
+ builder.addErrors(wrapper);
+
+ return builder.build();
+ }
+
+ private static MessageWrapper toMessageWrapper(LocalizableMessageList list) {
+ MessageList messageList = toMessageList(list);
+ return MessageWrapper.newBuilder()
+ .setMsgListArg(messageList)
+ .build();
+ }
+
+ private static MessageList toMessageList(LocalizableMessageList list) {
+ MessageList.Builder builder = MessageList.newBuilder();
+
+ for (LocalizableMessage msg : list.getMessages()) {
+ MessageWrapper wrapper = null;
+ if (msg instanceof SingleLocalizableMessage) {
+ wrapper = toMessageWrapper((SingleLocalizableMessage) msg);
+
+ } else if (msg instanceof LocalizableMessageList) {
+ wrapper = toMessageWrapper((LocalizableMessageList) msg);
+ }
+
+ builder.addArgs(wrapper);
+ }
+
+ return builder.build();
+ }
+
+ private static MessageWrapper toMessageWrapper(SingleLocalizableMessage msg) {
+ return MessageWrapper.newBuilder()
+ .setMsgArg(toMessage(msg))
+ .build();
+ }
+
+ private static Message toMessage(SingleLocalizableMessage msg) {
+ return Message.newBuilder()
+ .setKey(msg.getKey())
+ .addAllArgs(toMessageWrappers(msg.getArgs()))
+ .build();
+ }
+
+ private static Iterable extends MessageWrapper> toMessageWrappers(Object[] args) {
+ List list = new ArrayList<>();
+
+ for (Object arg : args) {
+ MessageWrapper wrapper;
+
+ if (arg instanceof SingleLocalizableMessage) {
+ wrapper = toMessageWrapper((SingleLocalizableMessage) arg);
+ } else if (arg instanceof LocalizableMessageList) {
+ wrapper = toMessageWrapper((LocalizableMessageList) arg);
+ } else {
+ wrapper = MessageWrapper.newBuilder()
+ .setStringArg(arg != null ? arg.toString() : "")
+ .build();
+ }
+
+ list.add(wrapper);
+ }
+
+ return list;
+ }
+}
\ No newline at end of file
diff --git a/self-services/src/main/proto/SelfResource.proto b/self-services/src/main/proto/SelfResource.proto
index 27873e2..4af6c16 100644
--- a/self-services/src/main/proto/SelfResource.proto
+++ b/self-services/src/main/proto/SelfResource.proto
@@ -14,11 +14,6 @@ service SelfServiceResource {
*/
rpc modifyProfile(ModifyProfileRequest) returns (ModifyProfileResponse);
- /**
- * Update user profile.
- */
- rpc updateProfile(UpdateProfileRequest) returns (UpdateProfileResponse);
-
/**
* Update credential with current password validating.
*/
@@ -47,26 +42,35 @@ message UserItemDelta {
}
enum UserItemPath {
- NAME = 0;
- FULL_NAME = 1;
- GIVEN_NAME = 2;
- FAMILY_NAME = 3;
- ADDITIONAL_NAME = 4;
- NICK_NAME = 5;
- HONORIFIC_PREFIX = 6;
- HONORIFIC_SUFFIX = 7;
- TITLE = 8;
- PREFERRED_LANGUAGE = 9;
- LOCALE = 10;
- TIMEZONE = 11;
- EMAIL_ADDRESS = 12;
- TELEPHONE_NUMBER = 13;
- EMPLOYEE_NUMBER = 14;
- EMPLOYEE_TYPE = 15;
- COST_CENTER = 16;
- ORGANIZATION = 17;
- ORGANIZATIONAL_UNIT = 18;
- LOCALITY = 19;
+ // ObjectType
+ F_NAME = 0;
+ F_DESCRIPTION = 1;
+ F_SUBTYPE = 2;
+ F_LIFECYCLE_STATE = 3;
+
+ // FocusType
+ F_JPEG_PHOTO = 20;
+ F_COST_CENTER = 21;
+ F_LOCALITY = 22;
+ F_PREFERRED_LANGUAGE = 23;
+ F_LOCALE = 24;
+ F_TIMEZONE = 25;
+ F_EMAIL_ADDRESS = 26;
+ F_TELEPHONE_NUMBER = 27;
+
+ // UserType
+ F_FULL_NAME = 40;
+ F_GIVEN_NAME = 41;
+ F_FAMILY_NAME = 42;
+ F_ADDITIONAL_NAME = 43;
+ F_NICK_NAME = 44;
+ F_HONORIFIC_PREFIX = 45;
+ F_HONORIFIC_SUFFIX = 46;
+ F_TITLE = 47;
+ F_EMPLOYEE_NUMBER = 48;
+ F_EMPLOYEE_TYPE = 49;
+ F_ORGANIZATION = 50;
+ F_ORGANIZATIONAL_UNIT = 51;
}
message ModifyProfileResponse {
@@ -154,3 +158,24 @@ message AssignOption {
message RequestRoleResponse {
}
+
+message Message {
+ string key = 1;
+ repeated MessageWrapper args = 2;
+}
+
+message MessageWrapper {
+ oneof arg {
+ Message msgArg = 3;
+ MessageList msgListArg = 4;
+ string stringArg = 5;
+ }
+}
+
+message MessageList {
+ repeated MessageWrapper args = 1;
+}
+
+message PolicyError {
+ repeated MessageWrapper errors = 1;
+}
\ No newline at end of file
diff --git a/self-services/src/test/java/TestBasicAuthClient.java b/self-services/src/test/java/TestBasicAuthClient.java
index 4a80d36..07f358e 100644
--- a/self-services/src/test/java/TestBasicAuthClient.java
+++ b/self-services/src/test/java/TestBasicAuthClient.java
@@ -26,7 +26,7 @@ public static void main(String[] args) throws UnsupportedEncodingException {
ModifyProfileRequest request = ModifyProfileRequest.newBuilder()
.addModifications(
UserItemDelta.newBuilder()
- .setName(UserItemPath.FAMILY_NAME)
+ .setName(UserItemPath.F_FAMILY_NAME)
.setValuesToReplace("Foo")
.build()
)
diff --git a/self-services/src/test/java/TestJWTAuthClient.java b/self-services/src/test/java/TestJWTAuthClient.java
index ef594e5..1f58c6d 100644
--- a/self-services/src/test/java/TestJWTAuthClient.java
+++ b/self-services/src/test/java/TestJWTAuthClient.java
@@ -37,7 +37,7 @@ public static void main(String[] args) throws UnsupportedEncodingException {
ModifyProfileRequest request = ModifyProfileRequest.newBuilder()
.addModifications(
UserItemDelta.newBuilder()
- .setName(UserItemPath.FAMILY_NAME)
+ .setName(UserItemPath.F_FAMILY_NAME)
.setValuesToReplace("Bar")
.build()
)
diff --git a/self-services/src/test/java/jp/openstandia/midpoint/grpc/MidPointGrpcTestRunner.java b/self-services/src/test/java/jp/openstandia/midpoint/grpc/MidPointGrpcTestRunner.java
new file mode 100644
index 0000000..b9f5874
--- /dev/null
+++ b/self-services/src/test/java/jp/openstandia/midpoint/grpc/MidPointGrpcTestRunner.java
@@ -0,0 +1,34 @@
+package jp.openstandia.midpoint.grpc;
+
+import com.evolveum.midpoint.web.boot.MidPointSpringApplication;
+import org.junit.jupiter.api.extension.AfterAllCallback;
+import org.junit.jupiter.api.extension.BeforeAllCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.springframework.util.FileSystemUtils;
+
+import java.io.File;
+
+public class MidPointGrpcTestRunner implements BeforeAllCallback, AfterAllCallback {
+
+ @Override
+ public void beforeAll(ExtensionContext extensionContext) throws Exception {
+ FileSystemUtils.deleteRecursively(new File("./target/midpoint"));
+
+ setProperites();
+
+ MidPointSpringApplication.main(new String[]{});
+ }
+
+ @Override
+ public void afterAll(ExtensionContext extensionContext) throws Exception {
+ setProperites();
+
+ MidPointSpringApplication.main(new String[]{"stop"});
+ }
+
+ public void setProperites() {
+ System.setProperty("file.encoding", "UTF-8");
+ System.setProperty("midpoint.home", "./target/midpoint");
+ System.setProperty("midpoint.logging.alt.enabled", "true");
+ }
+}
diff --git a/self-services/src/test/java/jp/openstandia/midpoint/grpc/SelfServiceResourceITest.java b/self-services/src/test/java/jp/openstandia/midpoint/grpc/SelfServiceResourceITest.java
new file mode 100644
index 0000000..f1014e9
--- /dev/null
+++ b/self-services/src/test/java/jp/openstandia/midpoint/grpc/SelfServiceResourceITest.java
@@ -0,0 +1,216 @@
+package jp.openstandia.midpoint.grpc;
+
+import com.google.protobuf.Descriptors;
+import io.grpc.*;
+import io.grpc.protobuf.ProtoUtils;
+import io.grpc.stub.MetadataUtils;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Base64;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@ExtendWith(MidPointGrpcTestRunner.class)
+class SelfServiceResourceITest {
+ static ManagedChannel channel;
+
+ @BeforeAll
+ static void init() {
+ channel = ManagedChannelBuilder.forAddress("localhost", 6565)
+ .usePlaintext()
+ .build();
+ }
+
+ @AfterAll
+ static void cleanup() {
+ channel.shutdownNow();
+ }
+
+ @Test
+ void modifyProfile() throws Exception {
+ SelfServiceResourceGrpc.SelfServiceResourceBlockingStub stub = SelfServiceResourceGrpc.newBlockingStub(channel);
+
+ String token = Base64.getEncoder().encodeToString("Administrator:5ecr3t".getBytes("UTF-8"));
+
+ Metadata headers = new Metadata();
+ headers.put(Constant.AuthorizationMetadataKey, "Basic " + token);
+// headers.put(Constant.SwitchToPrincipalByNameMetadataKey, "test");
+
+ stub = MetadataUtils.attachHeaders(stub, headers);
+
+ ModifyProfileRequest request = ModifyProfileRequest.newBuilder()
+ .addModifications(
+ UserItemDelta.newBuilder()
+ .setName(UserItemPath.F_FAMILY_NAME)
+ .setValuesToReplace("Foo")
+ .build()
+ )
+ .build();
+
+ stub.modifyProfile(request);
+ }
+
+ @Test
+ void updateCredential() throws Exception {
+ SelfServiceResourceGrpc.SelfServiceResourceBlockingStub stub = SelfServiceResourceGrpc.newBlockingStub(channel);
+
+ String token = Base64.getEncoder().encodeToString("Administrator:5ecr3t".getBytes("UTF-8"));
+
+ Metadata headers = new Metadata();
+ headers.put(Constant.AuthorizationMetadataKey, "Basic " + token);
+
+ stub = MetadataUtils.attachHeaders(stub, headers);
+
+ UpdateCredentialRequest request = UpdateCredentialRequest.newBuilder()
+ .setOld("5ecr3t")
+ .setNew("password")
+ .build();
+
+ stub.updateCredential(request);
+
+ // Update authorization header with new password
+ token = Base64.getEncoder().encodeToString("Administrator:password".getBytes("UTF-8"));
+ headers.put(Constant.AuthorizationMetadataKey, "Basic " + token);
+ stub = MetadataUtils.attachHeaders(stub, headers);
+
+ // Back to original password by forceUpdateCredential
+ ForceUpdateCredentialRequest forceReq = ForceUpdateCredentialRequest.newBuilder()
+ .setNew("5ecr3t")
+ .build();
+
+ stub.forceUpdateCredential(forceReq);
+ }
+
+ @Test
+ void passwordPolicyErrorWithSingleError() throws Exception {
+ SelfServiceResourceGrpc.SelfServiceResourceBlockingStub stub = SelfServiceResourceGrpc.newBlockingStub(channel);
+
+ String token = Base64.getEncoder().encodeToString("Administrator:5ecr3t".getBytes("UTF-8"));
+
+ Metadata headers = new Metadata();
+ headers.put(Constant.AuthorizationMetadataKey, "Basic " + token);
+
+ stub = MetadataUtils.attachHeaders(stub, headers);
+
+ UpdateCredentialRequest request = UpdateCredentialRequest.newBuilder()
+ .setOld("5ecr3t")
+ .setNew("123")
+ .build();
+
+ try {
+ stub.updateCredential(request);
+ fail("Should be thrown Exception of password policy error");
+ } catch (StatusRuntimeException e) {
+ assertEquals(Status.Code.INVALID_ARGUMENT, e.getStatus().getCode());
+
+ Metadata.Key POLICY_ERROR =
+ ProtoUtils.keyForProto(PolicyError.getDefaultInstance());
+
+ PolicyError policyError = e.getTrailers().get(POLICY_ERROR);
+
+ List errorsList = policyError.getErrorsList();
+ assertEquals(1, errorsList.size());
+
+ MessageWrapper wrapper = errorsList.get(0);
+ assertTrue(wrapper.hasMsgArg());
+
+ Message msg = wrapper.getMsgArg();
+ String errKey = msg.getKey();
+ assertEquals("PolicyViolationException.message.credentials.password", errKey);
+
+ List argsList = msg.getArgsList();
+ assertEquals(1, argsList.size());
+
+ MessageWrapper argsWrapper = argsList.get(0);
+ assertTrue(argsWrapper.hasMsgArg());
+
+ Message subMsgArgs = argsWrapper.getMsgArg();
+ String subErrKey = subMsgArgs.getKey();
+ assertEquals("ValuePolicy.minimalSizeNotMet", subErrKey);
+
+ List subMsgArgsList = subMsgArgs.getArgsList();
+ assertEquals(2, subMsgArgsList.size());
+
+ MessageWrapper subMsgArg1 = subMsgArgsList.get(0);
+ assertFalse(subMsgArg1.hasMsgArg());
+ assertFalse(subMsgArg1.hasMsgListArg());
+ assertEquals("5", subMsgArg1.getStringArg());
+
+ MessageWrapper subMsgArg2= subMsgArgsList.get(1);
+ assertFalse(subMsgArg2.hasMsgArg());
+ assertFalse(subMsgArg2.hasMsgListArg());
+ assertEquals("3", subMsgArg2.getStringArg());
+ }
+ }
+
+ @Test
+ void passwordPolicyErrorWithMultipleError() throws Exception {
+ SelfServiceResourceGrpc.SelfServiceResourceBlockingStub stub = SelfServiceResourceGrpc.newBlockingStub(channel);
+
+ String token = Base64.getEncoder().encodeToString("Administrator:5ecr3t".getBytes("UTF-8"));
+
+ Metadata headers = new Metadata();
+ headers.put(Constant.AuthorizationMetadataKey, "Basic " + token);
+
+ stub = MetadataUtils.attachHeaders(stub, headers);
+
+ UpdateCredentialRequest request = UpdateCredentialRequest.newBuilder()
+ .setOld("5ecr3t")
+ .setNew("1111")
+ .build();
+
+ try {
+ stub.updateCredential(request);
+ fail("Should be thrown Exception of password policy error");
+ } catch (StatusRuntimeException e) {
+ assertEquals(Status.Code.INVALID_ARGUMENT, e.getStatus().getCode());
+
+ Metadata.Key POLICY_ERROR =
+ ProtoUtils.keyForProto(PolicyError.getDefaultInstance());
+
+ PolicyError policyError = e.getTrailers().get(POLICY_ERROR);
+
+ List errorsList = policyError.getErrorsList();
+ assertEquals(1, errorsList.size());
+
+ MessageWrapper wrapper = errorsList.get(0);
+ assertTrue(wrapper.hasMsgArg());
+
+ Message msg = wrapper.getMsgArg();
+ String errKey = msg.getKey();
+ assertEquals("PolicyViolationException.message.credentials.password", errKey);
+
+ List argsList = msg.getArgsList();
+ assertEquals(1, argsList.size());
+
+ MessageWrapper argsWrapper = argsList.get(0);
+ assertFalse(argsWrapper.hasMsgArg(), "Should have multiple errors");
+ assertTrue(argsWrapper.hasMsgListArg(), "Should have multiple errors");
+
+ MessageList msgListArg = argsWrapper.getMsgListArg();
+ List subMsgList = msgListArg.getArgsList();
+ assertEquals(2, subMsgList.size(), "Should have multiple errors");
+
+ MessageWrapper argsWrapper1 = subMsgList.get(0);
+
+ Message subMsg1Args = argsWrapper1.getMsgArg();
+ String subErr1Key = subMsg1Args.getKey();
+ assertEquals("ValuePolicy.minimalSizeNotMet", subErr1Key);
+
+ MessageWrapper argsWrapper2 = subMsgList.get(1);
+
+ Message subMsg2Args = argsWrapper2.getMsgArg();
+ String subErr2Key = subMsg2Args.getKey();
+ assertEquals("ValuePolicy.minimalUniqueCharactersNotMet", subErr2Key);
+ }
+ }
+
+ @Test
+ void requestRole() {
+ }
+}
\ No newline at end of file
diff --git a/self-services/src/test/java/jp/openstandia/midpoint/grpc/TypeConverterTest.java b/self-services/src/test/java/jp/openstandia/midpoint/grpc/TypeConverterTest.java
new file mode 100644
index 0000000..1d8cb71
--- /dev/null
+++ b/self-services/src/test/java/jp/openstandia/midpoint/grpc/TypeConverterTest.java
@@ -0,0 +1,35 @@
+package jp.openstandia.midpoint.grpc;
+
+import com.evolveum.midpoint.prism.path.ItemName;
+import com.evolveum.midpoint.prism.polystring.PolyString;
+import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class TypeConverterTest {
+
+ @Test
+ public void toItemName() {
+ ItemName name = TypeConverter.toItemName(UserItemPath.F_NAME);
+ assertEquals(UserType.F_NAME, name, "Should get ItemName of ObjectType");
+
+ ItemName locality = TypeConverter.toItemName(UserItemPath.F_LOCALITY);
+ assertEquals(UserType.F_LOCALITY, locality, "Should get ItemName of FocusType");
+
+ ItemName fullName = TypeConverter.toItemName(UserItemPath.F_FULL_NAME);
+ assertEquals(UserType.F_FULL_NAME, fullName, "Should get ItemName of UserType");
+ }
+
+ @Test
+ public void toValue() {
+ Object foo = TypeConverter.toValue(UserItemPath.F_NAME, "foo");
+ assertEquals(PolyString.class, foo.getClass());
+
+ Object bar = TypeConverter.toValue(UserItemPath.F_EMPLOYEE_TYPE, "bar");
+ assertEquals(String.class, bar.getClass());
+
+ Object hoge = TypeConverter.toValue(UserItemPath.F_ORGANIZATION, "hoge");
+ assertEquals(PolyString.class, hoge.getClass());
+ }
+}
\ No newline at end of file
diff --git a/server/src/main/java/jp/openstandia/midpoint/grpc/MidPointGrpcService.java b/server/src/main/java/jp/openstandia/midpoint/grpc/MidPointGrpcService.java
index b525728..4bedf44 100644
--- a/server/src/main/java/jp/openstandia/midpoint/grpc/MidPointGrpcService.java
+++ b/server/src/main/java/jp/openstandia/midpoint/grpc/MidPointGrpcService.java
@@ -4,13 +4,17 @@
import com.evolveum.midpoint.security.api.HttpConnectionInformation;
import com.evolveum.midpoint.security.api.MidPointPrincipal;
import com.evolveum.midpoint.task.api.Task;
+import com.evolveum.midpoint.util.LocalizableMessage;
import com.evolveum.midpoint.util.QNameUtil;
+import com.evolveum.midpoint.util.SingleLocalizableMessage;
import com.evolveum.midpoint.util.exception.AuthorizationException;
import com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException;
import com.evolveum.midpoint.util.exception.ObjectNotFoundException;
import com.evolveum.midpoint.util.exception.PolicyViolationException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
+import com.lowagie.text.Meta;
+import io.grpc.Metadata;
import io.grpc.Status;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
@@ -47,10 +51,12 @@ default T runTask(MidPointTask task) {
.withCause(e)
.asRuntimeException();
} catch (PolicyViolationException e) {
+ Metadata metadata = handlePolicyViolationException(e);
+
throw Status.INVALID_ARGUMENT
.withDescription(e.getErrorTypeMessage())
.withCause(e)
- .asRuntimeException();
+ .asRuntimeException(metadata);
} catch (AuthorizationException e) {
throw Status.PERMISSION_DENIED
.withDescription(e.getErrorTypeMessage())
@@ -70,4 +76,9 @@ default T runTask(MidPointTask task) {
SecurityContextHolder.getContext().setAuthentication(null);
}
}
+
+ default Metadata handlePolicyViolationException(PolicyViolationException e) {
+ return new Metadata();
+ }
}
+
diff --git a/server/src/main/proto/UserResource.proto b/server/src/main/proto/UserResource.proto
deleted file mode 100644
index 1c7ddf2..0000000
--- a/server/src/main/proto/UserResource.proto
+++ /dev/null
@@ -1,69 +0,0 @@
-syntax = "proto3";
-
-option java_multiple_files = true;
-option java_package = "jp.openstandia.midpoint.grpc";
-
-package midpoint;
-
-/**
- * Provide services for an UserType resource.
- */
-service UserResourceService {
- /**
- * Update credential with current password validating.
- */
- rpc updateCredentialByName(UpdateCredentialByNameRequest) returns (UpdateCredentialResponse);
-
- /**
- * Force update credential.
- */
- rpc forceUpdateCredentialByName(ForceUpdateCredentialByNameRequest) returns (UpdateCredentialResponse);
-
- /**
- * Request role.
- */
- rpc requestRoleByName(RequestRoleByNameRequest) returns (RequestRoleResponse);
-}
-
-message UpdateCredentialByNameRequest {
- // Name of target user.
- string name = 1;
- // Current credential.
- string old = 2;
- // New credential.
- string new = 3;
-}
-
-message ForceUpdateCredentialByNameRequest {
- // Name of target user.
- string name = 1;
- // New credential.
- string new = 3;
-}
-
-message UpdateCredentialResponse {
-}
-
-message RequestRoleByNameRequest {
- // Name of initiator.
- string name = 1;
- // Assign requests.
- repeated AssignRequest assignRequest = 2;
-}
-
-message AssignRequest {
- // Oid of target user.
- string assignTargetOid = 1;
- // Oid of request role/organization/service.
- string requestObjectOid = 2;
- // Assign option
- AssignOption option = 3;
-}
-
-message AssignOption {
- // Oid of organization reference.
- string orgRef = 1;
-}
-
-message RequestRoleResponse {
-}