IGNITE-8428 Web Console: Implemented connection to secured cluster.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/c8be8c2b Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/c8be8c2b Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/c8be8c2b Branch: refs/heads/ignite-8446 Commit: c8be8c2b8e8a474a90735d6e9eaebc67c1c8e3de Parents: 523a871 Author: Alexey Kuznetsov <akuznet...@apache.org> Authored: Fri Jun 22 17:00:11 2018 +0700 Committer: Alexey Kuznetsov <akuznet...@apache.org> Committed: Fri Jun 22 17:00:11 2018 +0700 ---------------------------------------------------------------------- .../rest/AbstractRestProcessorSelfTest.java | 4 +- .../JettyRestProcessorAbstractSelfTest.java | 116 +------------ .../rest/JettyRestProcessorCommonSelfTest.java | 171 +++++++++++++++++++ .../rest/JettyRestProcessorSignedSelfTest.java | 6 +- .../JettyRestProcessorUnsignedSelfTest.java | 11 +- .../apache/ignite/IgniteSystemProperties.java | 13 +- .../processors/rest/GridRestProcessor.java | 94 ++++++---- .../visor/compute/VisorGatewayTask.java | 11 +- .../security/SecurityBasicPermissionSet.java | 4 +- 9 files changed, 262 insertions(+), 168 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/c8be8c2b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/AbstractRestProcessorSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/AbstractRestProcessorSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/AbstractRestProcessorSelfTest.java index c67d735..3a8afa4 100644 --- a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/AbstractRestProcessorSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/AbstractRestProcessorSelfTest.java @@ -29,7 +29,7 @@ import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; /** * Abstract class for REST protocols tests. */ -abstract class AbstractRestProcessorSelfTest extends GridCommonAbstractTest { +public abstract class AbstractRestProcessorSelfTest extends GridCommonAbstractTest { /** IP finder. */ private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true); @@ -55,7 +55,7 @@ abstract class AbstractRestProcessorSelfTest extends GridCommonAbstractTest { @Override protected void afterTest() throws Exception { jcache().clear(); - assertTrue(jcache().localSize() == 0); + assertEquals(0, jcache().localSize()); } /** {@inheritDoc} */ http://git-wip-us.apache.org/repos/asf/ignite/blob/c8be8c2b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java index 42f95db..25d5e89 100644 --- a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorAbstractSelfTest.java @@ -18,13 +18,8 @@ package org.apache.ignite.internal.processors.rest; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.LineNumberReader; import java.io.Serializable; import java.io.UnsupportedEncodingException; -import java.net.URL; -import java.net.URLConnection; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.sql.Date; @@ -34,7 +29,6 @@ import java.text.DateFormat; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; -import java.util.LinkedHashMap; import java.util.Locale; import java.util.Map; import java.util.Set; @@ -42,7 +36,6 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.ignite.IgniteCache; import org.apache.ignite.cache.CacheMode; @@ -148,7 +141,6 @@ import org.apache.ignite.lang.IgnitePredicate; import org.apache.ignite.lang.IgniteUuid; import org.apache.ignite.testframework.GridTestUtils; -import static org.apache.ignite.IgniteSystemProperties.IGNITE_JETTY_PORT; import static org.apache.ignite.cache.CacheMode.PARTITIONED; import static org.apache.ignite.cache.CacheMode.REPLICATED; import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_ASYNC; @@ -163,118 +155,22 @@ import static org.apache.ignite.internal.processors.rest.GridRestResponse.STATUS * Tests for Jetty REST protocol. */ @SuppressWarnings("unchecked") -public abstract class JettyRestProcessorAbstractSelfTest extends AbstractRestProcessorSelfTest { - /** Grid count. */ - private static final int GRID_CNT = 3; - +public abstract class JettyRestProcessorAbstractSelfTest extends JettyRestProcessorCommonSelfTest { /** Used to sent request charset. */ private static final String CHARSET = StandardCharsets.UTF_8.name(); - /** JSON to java mapper. */ - private static final ObjectMapper JSON_MAPPER = new GridJettyObjectMapper(); - /** {@inheritDoc} */ @Override protected void beforeTestsStarted() throws Exception { - System.setProperty(IGNITE_JETTY_PORT, Integer.toString(restPort())); - super.beforeTestsStarted(); initCache(); } /** {@inheritDoc} */ - @Override protected void afterTestsStopped() throws Exception { - System.clearProperty(IGNITE_JETTY_PORT); - } - - /** {@inheritDoc} */ @Override protected void beforeTest() throws Exception { grid(0).cache(DEFAULT_CACHE_NAME).removeAll(); } - /** {@inheritDoc} */ - @Override protected int gridCount() { - return GRID_CNT; - } - - /** - * @return Port to use for rest. Needs to be changed over time because Jetty has some delay before port unbind. - */ - protected abstract int restPort(); - - /** - * @return Test URL - */ - protected String restUrl() { - return "http://" + LOC_HOST + ":" + restPort() + "/ignite?"; - } - - /** - * @return Security enabled flag. Should be the same with {@code ctx.security().enabled()}. - */ - protected boolean securityEnabled() { - return false; - } - - /** - * Execute REST command and return result. - * - * @param params Command parameters. - * @return Returned content. - * @throws Exception If failed. - */ - protected String content(Map<String, String> params) throws Exception { - SB sb = new SB(restUrl()); - - for (Map.Entry<String, String> e : params.entrySet()) - sb.a(e.getKey()).a('=').a(e.getValue()).a('&'); - - URL url = new URL(sb.toString()); - - URLConnection conn = url.openConnection(); - - String signature = signature(); - - if (signature != null) - conn.setRequestProperty("X-Signature", signature); - - InputStream in = conn.getInputStream(); - - StringBuilder buf = new StringBuilder(256); - - try (LineNumberReader rdr = new LineNumberReader(new InputStreamReader(in, "UTF-8"))) { - for (String line = rdr.readLine(); line != null; line = rdr.readLine()) - buf.append(line); - } - - return buf.toString(); - } - - /** - * @param cacheName Optional cache name. - * @param cmd REST command. - * @param params Command parameters. - * @return Returned content. - * @throws Exception If failed. - */ - protected String content(String cacheName, GridRestCommand cmd, String... params) throws Exception { - Map<String, String> paramsMap = new LinkedHashMap<>(); - - if (cacheName != null) - paramsMap.put("cacheName", cacheName); - - paramsMap.put("cmd", cmd.key()); - - if (params != null) { - assertEquals(0, params.length % 2); - - for (int i = 0; i < params.length; i += 2) - paramsMap.put(params[i], params[i + 1]); - } - - return content(paramsMap); - } - /** * @param content Content to check. * @param err Error message. @@ -1497,7 +1393,7 @@ public abstract class JettyRestProcessorAbstractSelfTest extends AbstractRestPro JsonNode res = jsonResponse(ret); - assertEquals(GRID_CNT, res.size()); + assertEquals(gridCount(), res.size()); for (JsonNode node : res) { assertTrue(node.get("attributes").isNull()); @@ -2603,18 +2499,12 @@ public abstract class JettyRestProcessorAbstractSelfTest extends AbstractRestPro } /** - * @return Signature. - * @throws Exception If failed. - */ - protected abstract String signature() throws Exception; - - /** * @return True if any query cursor is available. */ private boolean queryCursorFound() { boolean found = false; - for (int i = 0; i < GRID_CNT; ++i) { + for (int i = 0; i < gridCount(); ++i) { Map<GridRestCommand, GridRestCommandHandler> handlers = GridTestUtils.getFieldValue(grid(i).context().rest(), "handlers"); http://git-wip-us.apache.org/repos/asf/ignite/blob/c8be8c2b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorCommonSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorCommonSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorCommonSelfTest.java new file mode 100644 index 0000000..2076d49 --- /dev/null +++ b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorCommonSelfTest.java @@ -0,0 +1,171 @@ +/* + * 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.rest; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.LineNumberReader; +import java.net.URL; +import java.net.URLConnection; +import java.util.LinkedHashMap; +import java.util.Map; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.apache.ignite.internal.processors.rest.protocols.http.jetty.GridJettyObjectMapper; +import org.apache.ignite.internal.util.typedef.internal.SB; + +import static org.apache.ignite.IgniteSystemProperties.IGNITE_JETTY_PORT; + +/** + * Base class for testing Jetty REST protocol. + */ +public abstract class JettyRestProcessorCommonSelfTest extends AbstractRestProcessorSelfTest { + /** Grid count. */ + private static final int GRID_CNT = 3; + + /** REST port. */ + private static final int DFLT_REST_PORT = 8091; + + /** JSON to java mapper. */ + protected static final ObjectMapper JSON_MAPPER = new GridJettyObjectMapper(); + + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + System.setProperty(IGNITE_JETTY_PORT, Integer.toString(restPort())); + + super.beforeTestsStarted(); + } + + /** {@inheritDoc} */ + @Override protected void afterTestsStopped() throws Exception { + System.clearProperty(IGNITE_JETTY_PORT); + } + + /** {@inheritDoc} */ + @Override protected int gridCount() { + return GRID_CNT; + } + + /** + * @return Port to use for rest. Needs to be changed over time because Jetty has some delay before port unbind. + */ + protected int restPort() { + return DFLT_REST_PORT; + } + + /** + * @return Test URL + */ + protected String restUrl() { + return "http://" + LOC_HOST + ":" + restPort() + "/ignite?"; + } + + /** + * @return Security enabled flag. Should be the same with {@code ctx.security().enabled()}. + */ + protected boolean securityEnabled() { + return false; + } + + /** + * @return Signature. + * @throws Exception If failed. + */ + protected abstract String signature() throws Exception; + + /** + * Execute REST command and return result. + * + * @param params Command parameters. + * @return Returned content. + * @throws Exception If failed. + */ + protected String content(Map<String, String> params) throws Exception { + SB sb = new SB(restUrl()); + + for (Map.Entry<String, String> e : params.entrySet()) + sb.a(e.getKey()).a('=').a(e.getValue()).a('&'); + + URL url = new URL(sb.toString()); + + URLConnection conn = url.openConnection(); + + String signature = signature(); + + if (signature != null) + conn.setRequestProperty("X-Signature", signature); + + InputStream in = conn.getInputStream(); + + StringBuilder buf = new StringBuilder(256); + + try (LineNumberReader rdr = new LineNumberReader(new InputStreamReader(in, "UTF-8"))) { + for (String line = rdr.readLine(); line != null; line = rdr.readLine()) + buf.append(line); + } + + return buf.toString(); + } + + /** + * @param cacheName Optional cache name. + * @param cmd REST command. + * @param params Command parameters. + * @return Returned content. + * @throws Exception If failed. + */ + protected String content(String cacheName, GridRestCommand cmd, String... params) throws Exception { + Map<String, String> paramsMap = new LinkedHashMap<>(); + + if (cacheName != null) + paramsMap.put("cacheName", cacheName); + + paramsMap.put("cmd", cmd.key()); + + if (params != null) { + assertEquals(0, params.length % 2); + + for (int i = 0; i < params.length; i += 2) + paramsMap.put(params[i], params[i + 1]); + } + + return content(paramsMap); + } + + /** + * @param json JSON content. + * @param field Field name in JSON object. + * @return Field value. + * @throws IOException If failed. + */ + protected String jsonField(String json, String field) throws IOException { + assertNotNull(json); + assertFalse(json.isEmpty()); + + JsonNode node = JSON_MAPPER.readTree(json); + + JsonNode fld = node.get(field); + + assertNotNull(fld); + + return fld.asText(); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/c8be8c2b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorSignedSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorSignedSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorSignedSelfTest.java index 00e4c68..3be99b4 100644 --- a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorSignedSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorSignedSelfTest.java @@ -82,11 +82,11 @@ public class JettyRestProcessorSignedSelfTest extends JettyRestProcessorAbstract @Override protected String signature() throws Exception { long ts = U.currentTimeMillis(); - String s = ts + ":" + REST_SECRET_KEY; - try { MessageDigest md = MessageDigest.getInstance("SHA-1"); + String s = ts + ":" + REST_SECRET_KEY; + md.update(s.getBytes()); String hash = Base64.getEncoder().encodeToString(md.digest()); @@ -97,4 +97,4 @@ public class JettyRestProcessorSignedSelfTest extends JettyRestProcessorAbstract throw new Exception("Failed to create authentication signature.", e); } } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/ignite/blob/c8be8c2b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorUnsignedSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorUnsignedSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorUnsignedSelfTest.java index 988cedf..c7ff0d2 100644 --- a/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorUnsignedSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/internal/processors/rest/JettyRestProcessorUnsignedSelfTest.java @@ -18,16 +18,11 @@ package org.apache.ignite.internal.processors.rest; /** - * + * Unsigned REST tests. */ public class JettyRestProcessorUnsignedSelfTest extends JettyRestProcessorAbstractSelfTest { /** {@inheritDoc} */ - @Override protected int restPort() { - return 8091; - } - - /** {@inheritDoc} */ - @Override protected String signature() throws Exception { + @Override protected String signature() { return null; } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/ignite/blob/c8be8c2b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java index 9ff216b..70b35bf 100644 --- a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java +++ b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java @@ -118,9 +118,12 @@ public final class IgniteSystemProperties { */ public static final String IGNITE_JETTY_LOG_NO_OVERRIDE = "IGNITE_JETTY_LOG_NO_OVERRIDE"; - /** This property allow rewriting default ({@code 30}) rest session expire time (in seconds). */ + /** This property allow rewriting default ({@code 30}) REST session expire time (in seconds). */ public static final String IGNITE_REST_SESSION_TIMEOUT = "IGNITE_REST_SESSION_TIMEOUT"; + /** This property allow rewriting default ({@code 300}) REST session security token expire time (in seconds). */ + public static final String IGNITE_REST_SECURITY_TOKEN_TIMEOUT = "IGNITE_REST_SECURITY_TOKEN_TIMEOUT"; + /** * This property allows to override maximum count of task results stored on one node * in REST processor. @@ -988,7 +991,7 @@ public final class IgniteSystemProperties { * The result is transformed to {@code int} using {@code Integer.parseInt()} method. * * @param name Name of the system property or environment variable. - * @param dflt Default value + * @param dflt Default value. * @return Integer value of the system property or environment variable. * Returns default value in case neither system property * nor environment variable with given name is found. @@ -1016,7 +1019,7 @@ public final class IgniteSystemProperties { * The result is transformed to {@code float} using {@code Float.parseFloat()} method. * * @param name Name of the system property or environment variable. - * @param dflt Default value + * @param dflt Default value. * @return Float value of the system property or environment variable. * Returns default value in case neither system property * nor environment variable with given name is found. @@ -1044,7 +1047,7 @@ public final class IgniteSystemProperties { * The result is transformed to {@code long} using {@code Long.parseLong()} method. * * @param name Name of the system property or environment variable. - * @param dflt Default value + * @param dflt Default value. * @return Integer value of the system property or environment variable. * Returns default value in case neither system property * nor environment variable with given name is found. @@ -1072,7 +1075,7 @@ public final class IgniteSystemProperties { * The result is transformed to {@code double} using {@code Double.parseDouble()} method. * * @param name Name of the system property or environment variable. - * @param dflt Default value + * @param dflt Default value. * @return Integer value of the system property or environment variable. * Returns default value in case neither system property * nor environment variable with given name is found. http://git-wip-us.apache.org/repos/asf/ignite/blob/c8be8c2b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestProcessor.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestProcessor.java index da5e5c2..d7a30f9 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/GridRestProcessor.java @@ -72,6 +72,7 @@ import org.apache.ignite.internal.util.typedef.internal.SB; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.internal.util.worker.GridWorker; import org.apache.ignite.internal.util.worker.GridWorkerFuture; +import org.apache.ignite.internal.visor.compute.VisorGatewayTask; import org.apache.ignite.internal.visor.util.VisorClusterGroupEmptyException; import org.apache.ignite.lang.IgniteBiTuple; import org.apache.ignite.lang.IgniteInClosure; @@ -81,6 +82,8 @@ import org.apache.ignite.plugin.security.SecurityException; import org.apache.ignite.plugin.security.SecurityPermission; import org.apache.ignite.thread.IgniteThread; +import static org.apache.ignite.IgniteSystemProperties.IGNITE_REST_SECURITY_TOKEN_TIMEOUT; +import static org.apache.ignite.IgniteSystemProperties.IGNITE_REST_SESSION_TIMEOUT; import static org.apache.ignite.IgniteSystemProperties.IGNITE_REST_START_ON_CLIENT; import static org.apache.ignite.internal.processors.rest.GridRestCommand.AUTHENTICATE; import static org.apache.ignite.internal.processors.rest.GridRestResponse.STATUS_AUTH_FAILED; @@ -99,8 +102,14 @@ public class GridRestProcessor extends GridProcessorAdapter { /** Delay between sessions timeout checks. */ private static final int SES_TIMEOUT_CHECK_DELAY = 1_000; - /** Default session timout. */ - private static final int DEFAULT_SES_TIMEOUT = 30_000; + /** Default session timeout, in seconds. */ + private static final int DFLT_SES_TIMEOUT = 30; + + /** The default interval used to invalidate sessions, in seconds. */ + private static final int DFLT_SES_TOKEN_INVALIDATE_INTERVAL = 5 * 60; + + /** Index of task name wrapped by VisorGatewayTask */ + private static final int WRAPPED_TASK_IDX = 1; /** Protocols. */ private final Collection<GridRestProtocol> protos = new ArrayList<>(); @@ -140,6 +149,9 @@ public class GridRestProcessor extends GridProcessorAdapter { /** Session time to live. */ private final long sesTtl; + /** Interval to invalidate session tokens. */ + private final long sesTokTtl; + /** * @param req Request. * @return Future. @@ -252,8 +264,8 @@ public class GridRestProcessor extends GridProcessorAdapter { SecurityContext secCtx0 = ses.secCtx; try { - if (secCtx0 == null) - ses.secCtx = secCtx0 = authenticate(req); + if (secCtx0 == null || ses.isTokenExpired(sesTokTtl)) + ses.secCtx = secCtx0 = authenticate(req, ses); authorize(req, secCtx0); } @@ -426,7 +438,7 @@ public class GridRestProcessor extends GridProcessorAdapter { UUID sesId = clientId2SesId.get(clientId); if (sesId == null || !sesId.equals(U.bytesToUuid(sesTok, 0))) - throw new IgniteCheckedException("Failed to handle request - unsupported case (misamatched " + + throw new IgniteCheckedException("Failed to handle request - unsupported case (mismatched " + "clientId and session token) [clientId=" + clientId + ", sesTok=" + U.byteArray2HexString(sesTok) + "]"); @@ -452,22 +464,8 @@ public class GridRestProcessor extends GridProcessorAdapter { public GridRestProcessor(GridKernalContext ctx) { super(ctx); - long sesExpTime0; - String sesExpTime = null; - - try { - sesExpTime = System.getProperty(IgniteSystemProperties.IGNITE_REST_SESSION_TIMEOUT); - - sesExpTime0 = sesExpTime != null ? Long.valueOf(sesExpTime) * 1000 : DEFAULT_SES_TIMEOUT; - } - catch (NumberFormatException ignore) { - U.warn(log, "Failed parsing IGNITE_REST_SESSION_TIMEOUT system variable [IGNITE_REST_SESSION_TIMEOUT=" - + sesExpTime + "]"); - - sesExpTime0 = DEFAULT_SES_TIMEOUT; - } - - sesTtl = sesExpTime0; + sesTtl = IgniteSystemProperties.getLong(IGNITE_REST_SESSION_TIMEOUT, DFLT_SES_TIMEOUT) * 1000; + sesTokTtl = IgniteSystemProperties.getLong(IGNITE_REST_SECURITY_TOKEN_TIMEOUT, DFLT_SES_TOKEN_INVALIDATE_INTERVAL) * 100; sesTimeoutCheckerThread = new IgniteThread(ctx.igniteInstanceName(), "session-timeout-worker", new GridWorker(ctx.igniteInstanceName(), "session-timeout-worker", log) { @@ -479,9 +477,8 @@ public class GridRestProcessor extends GridProcessorAdapter { Session ses = e.getValue(); if (ses.isTimedOut(sesTtl)) { - sesId2Ses.remove(ses.sesId, ses); - clientId2SesId.remove(ses.clientId, ses.sesId); + sesId2Ses.remove(ses.sesId, ses); } } } @@ -607,7 +604,7 @@ public class GridRestProcessor extends GridProcessorAdapter { return; if (req instanceof GridRestCacheRequest) { - GridRestCacheRequest req0 = (GridRestCacheRequest) req; + GridRestCacheRequest req0 = (GridRestCacheRequest)req; req0.key(interceptor.onReceive(req0.key())); req0.value(interceptor.onReceive(req0.value())); @@ -625,7 +622,7 @@ public class GridRestProcessor extends GridProcessorAdapter { } } else if (req instanceof GridRestTaskRequest) { - GridRestTaskRequest req0 = (GridRestTaskRequest) req; + GridRestTaskRequest req0 = (GridRestTaskRequest)req; List<Object> oldParams = req0.params(); @@ -731,7 +728,7 @@ public class GridRestProcessor extends GridProcessorAdapter { Object creds = req.credentials(); if (creds instanceof SecurityCredentials) - return (SecurityCredentials)creds; + return (SecurityCredentials)creds; if (creds instanceof String) { String credStr = (String)creds; @@ -757,7 +754,7 @@ public class GridRestProcessor extends GridProcessorAdapter { * @return Authentication subject context. * @throws IgniteCheckedException If authentication failed. */ - private SecurityContext authenticate(GridRestRequest req) throws IgniteCheckedException { + private SecurityContext authenticate(GridRestRequest req, Session ses) throws IgniteCheckedException { assert req.clientId() != null; AuthenticationContext authCtx = new AuthenticationContext(); @@ -766,10 +763,24 @@ public class GridRestProcessor extends GridProcessorAdapter { authCtx.subjectId(req.clientId()); authCtx.nodeAttributes(Collections.<String, Object>emptyMap()); authCtx.address(req.address()); - authCtx.credentials(credentials(req)); + + SecurityCredentials creds = credentials(req); + + if (creds.getLogin() == null) { + SecurityCredentials sesCreds = ses.creds; + + if (sesCreds != null) + creds = ses.creds; + } + else + ses.creds = creds; + + authCtx.credentials(creds); SecurityContext subjCtx = ctx.security().authenticate(authCtx); + ses.lastInvalidateTime.set(U.currentTimeMillis()); + if (subjCtx == null) { if (req.credentials() == null) throw new IgniteCheckedException("Failed to authenticate remote client (secure session SPI not set?): " + req); @@ -839,7 +850,13 @@ public class GridRestProcessor extends GridProcessorAdapter { case EXE: case RESULT: perm = SecurityPermission.TASK_EXECUTE; - name = ((GridRestTaskRequest)req).taskName(); + + GridRestTaskRequest taskReq = (GridRestTaskRequest)req; + name = taskReq.taskName(); + + // We should extract task name wrapped by VisorGatewayTask. + if (VisorGatewayTask.class.getName().equals(name)) + name = (String)taskReq.params().get(WRAPPED_TASK_IDX); break; @@ -880,7 +897,6 @@ public class GridRestProcessor extends GridProcessorAdapter { } /** - * * @return Whether or not REST is enabled. */ private boolean isRestEnabled() { @@ -972,7 +988,7 @@ public class GridRestProcessor extends GridProcessorAdapter { * Session. */ private static class Session { - /** Expiration flag. It's a final state of lastToucnTime. */ + /** Expiration flag. It's a final state of lastTouchTime. */ private static final Long TIMEDOUT_FLAG = 0L; /** Client id. */ @@ -987,12 +1003,18 @@ public class GridRestProcessor extends GridProcessorAdapter { */ private final AtomicLong lastTouchTime = new AtomicLong(U.currentTimeMillis()); + /** Time when session token was invalidated last time. */ + private final AtomicLong lastInvalidateTime = new AtomicLong(U.currentTimeMillis()); + /** Security context. */ private volatile SecurityContext secCtx; /** Authorization context. */ private volatile AuthorizationContext authCtx; + /** Credentials that can be used for security token invalidation.*/ + private volatile SecurityCredentials creds; + /** * @param clientId Client ID. * @param sesId session ID. @@ -1048,6 +1070,16 @@ public class GridRestProcessor extends GridProcessorAdapter { } /** + * Checks if session token should be invalidated. + * + * @param sesTokTtl Session token expire time. + * @return {@code true} if session token should be invalidated. + */ + boolean isTokenExpired(long sesTokTtl) { + return U.currentTimeMillis() - lastInvalidateTime.get() > sesTokTtl; + } + + /** * Checks whether session at expired state (EXPIRATION_FLAG) or not, if not then tries to update last touch time. * * @return {@code False} if session timed out (not successfully touched). http://git-wip-us.apache.org/repos/asf/ignite/blob/c8be8c2b/modules/core/src/main/java/org/apache/ignite/internal/visor/compute/VisorGatewayTask.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/compute/VisorGatewayTask.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/compute/VisorGatewayTask.java index ee0a54b..e213bf4 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/visor/compute/VisorGatewayTask.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/compute/VisorGatewayTask.java @@ -185,8 +185,9 @@ public class VisorGatewayTask implements ComputeTask<Object[], Object> { Class<?> valCls = Class.forName(valClsName); - return new IgniteBiTuple<>(toObject(keyCls, (String)argument(startIdx + 2)), - toObject(valCls, (String)argument(startIdx + 3))); + return new IgniteBiTuple<>( + toObject(keyCls, argument(startIdx + 2)), + toObject(valCls, argument(startIdx + 3))); } if (cls == Map.class) { @@ -229,8 +230,10 @@ public class VisorGatewayTask implements ComputeTask<Object[], Object> { Class<?> v2Cls = Class.forName(v2ClsName); Class<?> v3Cls = Class.forName(v3ClsName); - return new GridTuple3<>(toObject(v1Cls, (String)argument(startIdx + 3)), toObject(v2Cls, - (String)argument(startIdx + 4)), toObject(v3Cls, (String)argument(startIdx + 5))); + return new GridTuple3<>( + toObject(v1Cls, argument(startIdx + 3)), + toObject(v2Cls, argument(startIdx + 4)), + toObject(v3Cls, argument(startIdx + 5))); } return toObject(cls, arg); http://git-wip-us.apache.org/repos/asf/ignite/blob/c8be8c2b/modules/core/src/main/java/org/apache/ignite/plugin/security/SecurityBasicPermissionSet.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/plugin/security/SecurityBasicPermissionSet.java b/modules/core/src/main/java/org/apache/ignite/plugin/security/SecurityBasicPermissionSet.java index 370eadd..fa7c748 100644 --- a/modules/core/src/main/java/org/apache/ignite/plugin/security/SecurityBasicPermissionSet.java +++ b/modules/core/src/main/java/org/apache/ignite/plugin/security/SecurityBasicPermissionSet.java @@ -36,8 +36,8 @@ import static org.apache.ignite.internal.processors.security.SecurityUtils.isSec import static org.apache.ignite.internal.processors.security.SecurityUtils.serializeVersion; /** - * Simple implementation of {@link SecurityPermissionSet} interface. Provides - * convenient way to specify permission set in the XML configuration. + * Simple implementation of {@link SecurityPermissionSet} interface. + * Provides convenient way to specify permission set in the XML configuration. */ public class SecurityBasicPermissionSet implements SecurityPermissionSet { /** Serial version uid. */