diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContext.java b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContext.java index 6953d8b853891..4050634f90b61 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContext.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContext.java @@ -307,7 +307,7 @@ private int mergeUpdatedAttributeBits(AttributeValueHolder[] attrVals) { } /** Immutable container that stores an attribute and its corresponding value. */ - private static class AttributeValueHolder { + public static class AttributeValueHolder { /** */ private final OperationContextAttribute attr; diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContextAttribute.java b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContextAttribute.java index 499d241d9ccba..2a80df28d54d3 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContextAttribute.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContextAttribute.java @@ -32,7 +32,7 @@ public class OperationContextAttribute { static final AtomicInteger ID_GEN = new AtomicInteger(); /** */ - static final int MAX_ATTR_CNT = Integer.SIZE; + public static final int MAX_ATTR_CNT = Integer.SIZE; /** */ private final int bitmask; @@ -41,7 +41,7 @@ public class OperationContextAttribute { @Nullable private final T initVal; /** */ - private OperationContextAttribute(int bitmask, @Nullable T initVal) { + public OperationContextAttribute(int bitmask, @Nullable T initVal) { this.bitmask = bitmask; this.initVal = initVal; } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java b/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java index fc9e3e1145970..949800eaf84f1 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java @@ -28,7 +28,6 @@ import org.apache.ignite.internal.managers.communication.CompressedMessage; import org.apache.ignite.internal.managers.communication.ErrorMessage; import org.apache.ignite.internal.managers.communication.GridIoMessage; -import org.apache.ignite.internal.managers.communication.GridIoSecurityAwareMessage; import org.apache.ignite.internal.managers.communication.GridIoUserMessage; import org.apache.ignite.internal.managers.communication.IgniteIoTestMessage; import org.apache.ignite.internal.managers.communication.SessionChannelMessage; @@ -229,6 +228,7 @@ import org.apache.ignite.internal.processors.query.stat.messages.StatisticsResponse; import org.apache.ignite.internal.processors.rest.handlers.task.GridTaskResultRequest; import org.apache.ignite.internal.processors.rest.handlers.task.GridTaskResultResponse; +import org.apache.ignite.internal.processors.security.SecuritySubjectMessage; import org.apache.ignite.internal.processors.service.ServiceChangeBatchRequest; import org.apache.ignite.internal.processors.service.ServiceClusterDeploymentResult; import org.apache.ignite.internal.processors.service.ServiceClusterDeploymentResultBatch; @@ -602,7 +602,7 @@ public CoreMessagesProvider(Marshaller dfltMarsh, Marshaller schemaAwareMarsh, C withNoSchema(GridIoMessage.class); withNoSchema(IgniteIoTestMessage.class); withSchema(GridIoUserMessage.class); - withSchema(GridIoSecurityAwareMessage.class); + ++msgIdx; // Former GridIoSecurityAwareMessage. withNoSchema(RecoveryLastReceivedMessage.class); withNoSchema(TcpInverseConnectionResponseMessage.class); withNoSchema(SessionChannelMessage.class); @@ -670,6 +670,12 @@ public CoreMessagesProvider(Marshaller dfltMarsh, Marshaller schemaAwareMarsh, C withNoSchema(PartitionHashRecord.class); withNoSchema(TransactionsHashRecord.class); + // [13400 - 13600]: Operation context messages. + msgIdx = 13400; + withNoSchema(OperationContexAttributeMessage.class); + withNoSchema(OperationContexMessage.class); + withNoSchema(SecuritySubjectMessage.class); + assert msgIdx <= MAX_MESSAGE_ID; } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/OperationContexAttributeMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/OperationContexAttributeMessage.java new file mode 100644 index 0000000000000..bb847fa744c43 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/OperationContexAttributeMessage.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal; + +import org.apache.ignite.internal.thread.context.OperationContextAttribute; +import org.apache.ignite.plugin.extensions.communication.Message; + +/** Transport of {@link OperationContextAttribute}. */ +public class OperationContexAttributeMessage implements Message { + /** Operation context attribute type. */ + @Order(0) + OperationContextAttributeType type; + + /** Operation context attribute value. */ + @Order(1) + Message val; + + /** Empty constructor for serialization purposes. */ + public OperationContexAttributeMessage() { + // No-op. + } + + /** Creates operation context attribute message. */ + public OperationContexAttributeMessage(OperationContextAttributeType type, Message val) { + this.type = type; + this.val = val; + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/OperationContexMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/OperationContexMessage.java new file mode 100644 index 0000000000000..562cde21a5f4a --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/OperationContexMessage.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal; + +import java.util.ArrayList; +import java.util.List; +import org.apache.ignite.internal.thread.context.OperationContext; +import org.apache.ignite.internal.thread.context.OperationContextAttribute; +import org.apache.ignite.plugin.extensions.communication.Message; +import org.jetbrains.annotations.Nullable; + +/** Transport of {@link OperationContext}. */ +public class OperationContexMessage implements Message { + /** Expected maximal number of operation context attributes. Is for message size optimization. */ + private static final int DFLT_EXPECTED_MAX_ATTRIBUTES_NUMBER = 5; + + /** Effective operation context attributes and their values. */ + @Order(0) + List opCtxAttrs; + + /** + * Mapping of the attributes: attribute id -> effective attribute index + 1. + * If attributes index is 0, corresponding attribute is not set. + */ + @Order(1) + byte[] attrsMapping = new byte[OperationContextAttribute.MAX_ATTR_CNT]; + + /** Empty constructor for serialization purposes. */ + public OperationContexMessage() { + // No-op. + } + + /** */ + public boolean hasAttribute(OperationContextAttributeType attrType) { + assert attrType.id() >= 0 && attrType.id() < attrsMapping.length; + + return attrsMapping[attrType.id()] > 0; + } + + /** */ + public @Nullable T attributeValue(OperationContextAttributeType attrType) { + assert attrType.id() >= 0 && attrType.id() < attrsMapping.length; + + byte idx = attrsMapping[attrType.id()]; + + if (idx < 1) + return null; + + --idx; + + assert idx < opCtxAttrs.size(); + + OperationContexAttributeMessage attrMsg = opCtxAttrs.get(idx); + + assert attrMsg != null; + assert attrMsg.type == attrType; + + return (T)attrMsg.val; + } + + /** */ + public static OperationContexMessage enrich( + @Nullable OperationContexMessage msg, + OperationContextAttributeType attrType, + Message attrVal + ) { + if (msg == null) { + msg = new OperationContexMessage(); + + msg.opCtxAttrs = new ArrayList<>(DFLT_EXPECTED_MAX_ATTRIBUTES_NUMBER); + } + + assert attrType.id() >= 0 && attrType.id() < msg.attrsMapping.length; + + msg.opCtxAttrs.add(new OperationContexAttributeMessage(attrType, attrVal)); + + msg.attrsMapping[attrType.id()] = (byte)msg.opCtxAttrs.size(); + + return msg; + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/OperationContextAttributeType.java b/modules/core/src/main/java/org/apache/ignite/internal/OperationContextAttributeType.java new file mode 100644 index 0000000000000..144c7e862cafe --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/OperationContextAttributeType.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal; + +import org.apache.ignite.internal.processors.security.SecuritySubjectMessage; +import org.apache.ignite.internal.thread.context.OperationContextAttribute; +import org.apache.ignite.plugin.extensions.communication.Message; +import org.jetbrains.annotations.Nullable; + +/** + * Type of {@link OperationContextAttribute}. + */ +public enum OperationContextAttributeType { + /** */ + SECURITY(SecuritySubjectMessage.class); + + /** Attribute value type. */ + private final Class valType; + + /** */ + private OperationContextAttributeType(Class valType) { + this.valType = valType; + } + + /** */ + public OperationContextAttribute create(OperationContextAttributeType type, @Nullable T initVal) { + assert type == null || initVal.getClass().isAssignableFrom(type()); + + return new OperationContextAttribute<>(type.id(), initVal); + } + + /** */ + public Class type() { + return valType; + } + + /** + * Attribute id (number). Limited by {@link OperationContextAttribute#MAX_ATTR_CNT}. + * + * @see OperationContextAttribute#bitmask() + */ + public byte id() { + assert (byte)ordinal() < OperationContextAttribute.MAX_ATTR_CNT; + + return (byte)ordinal(); + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java index 3acf503561ad8..ceb9f7c38886d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java @@ -83,6 +83,8 @@ import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.IgniteKernal; import org.apache.ignite.internal.NodeStoppingException; +import org.apache.ignite.internal.OperationContexMessage; +import org.apache.ignite.internal.OperationContextAttributeType; import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException; import org.apache.ignite.internal.direct.DirectMessageReader; import org.apache.ignite.internal.direct.DirectMessageWriter; @@ -97,6 +99,7 @@ import org.apache.ignite.internal.processors.cache.persistence.file.RandomAccessFileIOFactory; import org.apache.ignite.internal.processors.platform.message.PlatformMessageFilter; import org.apache.ignite.internal.processors.pool.PoolProcessor; +import org.apache.ignite.internal.processors.security.SecuritySubjectMessage; import org.apache.ignite.internal.processors.timeout.GridTimeoutObject; import org.apache.ignite.internal.processors.tracing.MTC; import org.apache.ignite.internal.processors.tracing.MTC.TraceSurroundings; @@ -137,7 +140,6 @@ import org.apache.ignite.spi.communication.tcp.internal.ConnectionRequestor; import org.apache.ignite.spi.communication.tcp.internal.TcpConnectionRequestDiscoveryMessage; import org.apache.ignite.spi.communication.tcp.internal.TcpInverseConnectionResponseMessage; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import static org.apache.ignite.events.EventType.EVT_NODE_FAILED; @@ -2025,11 +2027,8 @@ private long getInverseConnectionWaitTimeout() { return ctx.config().getFailureDetectionTimeout(); } - /** - * @return One of two message wrappers. The first is {@link GridIoMessage}, the second is secured version {@link - * GridIoSecurityAwareMessage}. - */ - private @NotNull GridIoMessage createGridIoMessage( + /** @return A {@link GridIoMessage} wrapper for {@code msg}. */ + private GridIoMessage createGridIoMessage( Object topic, Message msg, byte plc, @@ -2037,16 +2036,18 @@ private long getInverseConnectionWaitTimeout() { long timeout, boolean skipOnTimeout ) { + GridIoMessage res = new GridIoMessage(plc, topic, msg, ordered, timeout, skipOnTimeout); + if (ctx.security().enabled()) { - UUID secSubjId = null; + assert res.opCtxMsg == null : "Several context operation attributes aren't supported yet."; - if (!ctx.security().isDefaultContext()) - secSubjId = ctx.security().securityContext().subject().id(); + UUID secSubjId = ctx.security().isDefaultContext() ? null : ctx.security().securityContext().subject().id(); - return new GridIoSecurityAwareMessage(secSubjId, plc, topic, msg, ordered, timeout, skipOnTimeout); + res.opCtxMsg = OperationContexMessage.enrich(res.opCtxMsg, OperationContextAttributeType.SECURITY, + new SecuritySubjectMessage(secSubjId)); } - return new GridIoMessage(plc, topic, msg, ordered, timeout, skipOnTimeout); + return res; } /** @@ -4236,9 +4237,12 @@ public long binLatencyMcs() { */ private UUID secSubjId(GridIoMessage msg) { if (ctx.security().enabled()) { - assert msg instanceof GridIoSecurityAwareMessage; + assert msg.opCtxMsg != null; + assert msg.opCtxMsg.hasAttribute(OperationContextAttributeType.SECURITY); + + SecuritySubjectMessage secSubjMsg = msg.opCtxMsg.attributeValue(OperationContextAttributeType.SECURITY); - return ((GridIoSecurityAwareMessage)msg).securitySubjectId(); + return secSubjMsg.id; } return null; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessage.java index 8cc6c106cf22e..f6a099481ac2b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessage.java @@ -19,6 +19,7 @@ import org.apache.ignite.internal.ExecutorAwareMessage; import org.apache.ignite.internal.GridTopicMessage; +import org.apache.ignite.internal.OperationContexMessage; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.cache.GridCacheMessage; import org.apache.ignite.internal.processors.datastreamer.DataStreamerRequest; @@ -64,6 +65,11 @@ public class GridIoMessage implements Message, SpanTransport { @Order(6) byte[] span; + /** Effective operation context attributes. */ + @Order(7) + @GridToStringInclude + public @Nullable OperationContexMessage opCtxMsg; + /** * Default constructor. */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoSecurityAwareMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoSecurityAwareMessage.java deleted file mode 100644 index d1a6040d3d682..0000000000000 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoSecurityAwareMessage.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.ignite.internal.managers.communication; - -import java.util.UUID; -import org.apache.ignite.internal.Order; -import org.apache.ignite.plugin.extensions.communication.Message; - -/** - * - */ -public class GridIoSecurityAwareMessage extends GridIoMessage { - /** Security subject ID that will be used during message processing on a remote node. */ - @Order(0) - UUID secSubjId; - - /** - * Default constructor. - */ - public GridIoSecurityAwareMessage() { - // No-op. - } - - /** - * @param secSubjId Security subject ID. - * @param plc Policy. - * @param topic Communication topic. - * @param msg Message. - * @param ordered Message ordered flag. - * @param timeout Timeout. - * @param skipOnTimeout Whether message can be skipped on timeout. - */ - public GridIoSecurityAwareMessage( - UUID secSubjId, - byte plc, - Object topic, - Message msg, - boolean ordered, - long timeout, - boolean skipOnTimeout - ) { - super(plc, topic, msg, ordered, timeout, skipOnTimeout); - - this.secSubjId = secSubjId; - } - - /** - * @return Security subject ID. - */ - UUID securitySubjectId() { - return secSubjId; - } -} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/security/SecuritySubjectMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/security/SecuritySubjectMessage.java new file mode 100644 index 0000000000000..a14029562d188 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/security/SecuritySubjectMessage.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal.processors.security; + +import java.io.Serializable; +import java.util.UUID; +import org.apache.ignite.internal.OperationContextAttributeType; +import org.apache.ignite.internal.Order; +import org.apache.ignite.plugin.extensions.communication.Message; +import org.jetbrains.annotations.Nullable; + +/** A message for {@link OperationContextAttributeType#SECURITY}. */ +public class SecuritySubjectMessage implements Message, Serializable { + /** */ + private static final long serialVersionUID = 0L; + + /** Security subject identifier. */ + @Order(0) + public @Nullable UUID id; + + /** Empty constructor for serialization purposes */ + public SecuritySubjectMessage() { + // No-op. + } + + /** */ + public SecuritySubjectMessage(@Nullable UUID id) { + this.id = id; + } +} diff --git a/modules/core/src/main/resources/META-INF/classnames.properties b/modules/core/src/main/resources/META-INF/classnames.properties index e009043efb02d..4b550be9e993b 100644 --- a/modules/core/src/main/resources/META-INF/classnames.properties +++ b/modules/core/src/main/resources/META-INF/classnames.properties @@ -705,7 +705,6 @@ org.apache.ignite.internal.managers.checkpoint.GridCheckpointManager$CheckpointS org.apache.ignite.internal.managers.checkpoint.GridCheckpointRequest org.apache.ignite.internal.managers.communication.GridIoManager$ConcurrentHashMap0 org.apache.ignite.internal.managers.communication.GridIoMessage -org.apache.ignite.internal.managers.communication.GridIoSecurityAwareMessage org.apache.ignite.internal.managers.communication.GridIoUserMessage org.apache.ignite.internal.managers.communication.IgniteIoTestMessage org.apache.ignite.internal.managers.communication.SessionChannelMessage diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/IgniteSecurityProcessorTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/IgniteSecurityProcessorTest.java index 32da11cbc7da6..1936660a570e0 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/security/IgniteSecurityProcessorTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/security/IgniteSecurityProcessorTest.java @@ -22,8 +22,10 @@ import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.internal.IgniteDiagnosticRequest; import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.OperationContexMessage; +import org.apache.ignite.internal.OperationContextAttributeType; import org.apache.ignite.internal.managers.GridManagerAdapter; -import org.apache.ignite.internal.managers.communication.GridIoSecurityAwareMessage; +import org.apache.ignite.internal.managers.communication.GridIoMessage; import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi; import org.apache.ignite.testframework.GridTestUtils; import org.apache.ignite.testframework.ListeningTestLogger; @@ -76,15 +78,12 @@ public void testThrowIllegalStateExceptionIfNodeNotFoundInDiscoCache() throws Ex listeningLog.registerListener(logPattern); - spi.sendMessage(srv.localNode(), new GridIoSecurityAwareMessage( - UUID.randomUUID(), - PUBLIC_POOL, - TOPIC_CACHE, - new IgniteDiagnosticRequest(), - false, - 0, - false - )); + GridIoMessage msg = new GridIoMessage(PUBLIC_POOL, TOPIC_CACHE, new IgniteDiagnosticRequest(), false, 0, false); + + msg.opCtxMsg = OperationContexMessage.enrich(null, OperationContextAttributeType.SECURITY, + new SecuritySubjectMessage(UUID.randomUUID())); + + spi.sendMessage(srv.localNode(), msg); GridTestUtils.waitForCondition(logPattern::check, getTestTimeout()); }