ozone.s3g.metrics.percentiles.intervals.seconds
60
diff --git a/hadoop-ozone/dist/src/main/compose/ozonesecure/docker-compose.yaml b/hadoop-ozone/dist/src/main/compose/ozonesecure/docker-compose.yaml
index f3e372964bb7..612e188696ec 100644
--- a/hadoop-ozone/dist/src/main/compose/ozonesecure/docker-compose.yaml
+++ b/hadoop-ozone/dist/src/main/compose/ozonesecure/docker-compose.yaml
@@ -94,6 +94,7 @@ services:
- ./krb5.conf:/etc/krb5.conf
ports:
- 9878:9878
+ - 19878:19878
env_file:
- ./docker-config
command: ["/opt/hadoop/bin/ozone","s3g", "-Dozone.om.transport.class=${OZONE_S3_OM_TRANSPORT:-org.apache.hadoop.ozone.om.protocolPB.GrpcOmTransportFactory}"]
diff --git a/hadoop-ozone/dist/src/main/compose/ozonesecure/docker-config b/hadoop-ozone/dist/src/main/compose/ozonesecure/docker-config
index 5daf6c11fc9b..822e8f0a393c 100644
--- a/hadoop-ozone/dist/src/main/compose/ozonesecure/docker-config
+++ b/hadoop-ozone/dist/src/main/compose/ozonesecure/docker-config
@@ -93,6 +93,7 @@ OZONE-SITE.XML_hdds.datanode.kerberos.keytab.file=/etc/security/keytabs/dn.keyta
OZONE-SITE.XML_ozone.security.http.kerberos.enabled=true
OZONE-SITE.XML_ozone.s3g.secret.http.enabled=true
+OZONE-SITE.XML_ozone.s3g.sts.http.enabled=true
OZONE-SITE.XML_ozone.http.filter.initializers=org.apache.hadoop.security.AuthenticationFilterInitializer
OZONE-SITE.XML_ozone.om.http.auth.type=kerberos
@@ -100,6 +101,7 @@ OZONE-SITE.XML_hdds.scm.http.auth.type=kerberos
OZONE-SITE.XML_hdds.datanode.http.auth.type=kerberos
OZONE-SITE.XML_ozone.s3g.http.auth.type=kerberos
OZONE-SITE.XML_ozone.s3g.secret.http.auth.type=kerberos
+OZONE-SITE.XML_ozone.s3g.sts.http.auth.type=kerberos
OZONE-SITE.XML_ozone.httpfs.http.auth.type=kerberos
OZONE-SITE.XML_ozone.recon.http.auth.type=kerberos
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestOzoneConfigurationFields.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestOzoneConfigurationFields.java
index c699a6f6fafc..49a18062966a 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestOzoneConfigurationFields.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/TestOzoneConfigurationFields.java
@@ -29,7 +29,8 @@
import org.apache.hadoop.ozone.om.OMConfigKeys;
import org.apache.hadoop.ozone.recon.ReconServerConfigKeys;
import org.apache.hadoop.ozone.s3.S3GatewayConfigKeys;
-import org.apache.hadoop.ozone.s3secret.S3SecretConfigKeys;
+import org.apache.hadoop.ozone.s3web.s3secret.S3SecretConfigKeys;
+import org.apache.hadoop.ozone.s3web.s3sts.S3STSConfigKeys;
/**
* Tests if configuration constants documented in ozone-defaults.xml.
@@ -45,6 +46,7 @@ public void initializeMemberVariables() {
ReconConfigKeys.class, ReconServerConfigKeys.class,
S3GatewayConfigKeys.class,
S3SecretConfigKeys.class,
+ S3STSConfigKeys.class,
SCMHTTPServerConfig.class,
SCMHTTPServerConfig.ConfigStrings.class,
ScmConfig.ConfigStrings.class
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/S3GatewayWebAdminServer.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/S3GatewayWebAdminServer.java
index f87343cfb92b..e3117d593000 100644
--- a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/S3GatewayWebAdminServer.java
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/S3GatewayWebAdminServer.java
@@ -29,10 +29,10 @@
import static org.apache.hadoop.ozone.s3.S3GatewayConfigKeys.OZONE_S3G_WEBADMIN_HTTP_BIND_PORT_DEFAULT;
import static org.apache.hadoop.ozone.s3.S3GatewayConfigKeys.OZONE_S3G_WEBADMIN_HTTP_ENABLED_KEY;
import static org.apache.hadoop.ozone.s3.S3GatewayConfigKeys.OZONE_S3G_WEB_AUTHENTICATION_KERBEROS_PRINCIPAL;
-import static org.apache.hadoop.ozone.s3secret.S3SecretConfigKeys.OZONE_S3G_SECRET_HTTP_AUTH_TYPE_DEFAULT;
-import static org.apache.hadoop.ozone.s3secret.S3SecretConfigKeys.OZONE_S3G_SECRET_HTTP_AUTH_TYPE_KEY;
-import static org.apache.hadoop.ozone.s3secret.S3SecretConfigKeys.OZONE_S3G_SECRET_HTTP_ENABLED_KEY;
-import static org.apache.hadoop.ozone.s3secret.S3SecretConfigKeys.OZONE_S3G_SECRET_HTTP_ENABLED_KEY_DEFAULT;
+import static org.apache.hadoop.ozone.s3web.s3secret.S3SecretConfigKeys.OZONE_S3G_SECRET_HTTP_AUTH_TYPE_DEFAULT;
+import static org.apache.hadoop.ozone.s3web.s3secret.S3SecretConfigKeys.OZONE_S3G_SECRET_HTTP_AUTH_TYPE_KEY;
+import static org.apache.hadoop.ozone.s3web.s3secret.S3SecretConfigKeys.OZONE_S3G_SECRET_HTTP_ENABLED_KEY;
+import static org.apache.hadoop.ozone.s3web.s3secret.S3SecretConfigKeys.OZONE_S3G_SECRET_HTTP_ENABLED_KEY_DEFAULT;
import static org.apache.hadoop.security.authentication.server.AuthenticationFilter.AUTH_TYPE;
import com.google.common.base.Strings;
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/signature/StringToSignProducer.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/signature/StringToSignProducer.java
index ea460f62d494..136f9771ed95 100644
--- a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/signature/StringToSignProducer.java
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/signature/StringToSignProducer.java
@@ -118,7 +118,6 @@ public static String createSignatureBase(
}
strToSign.append(signatureInfo.getDateTime()).append(NEWLINE);
strToSign.append(credentialScope).append(NEWLINE);
-
String canonicalRequest = buildCanonicalRequest(
scheme,
method,
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/Application.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/Application.java
similarity index 91%
rename from hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/Application.java
rename to hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/Application.java
index 77ba872e5199..1fcaba763bce 100644
--- a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/Application.java
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/Application.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package org.apache.hadoop.ozone.s3secret;
+package org.apache.hadoop.ozone.s3web;
import org.glassfish.jersey.server.ResourceConfig;
@@ -24,6 +24,6 @@
*/
public class Application extends ResourceConfig {
public Application() {
- packages("org.apache.hadoop.ozone.s3secret");
+ packages(true, "org.apache.hadoop.ozone.s3web");
}
}
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/package-info.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/package-info.java
new file mode 100644
index 000000000000..fc06957acedf
--- /dev/null
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/**
+ * This package contains the top level generic classes of s3 web gateway.
+ */
+package org.apache.hadoop.ozone.s3web;
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/S3AdminEndpoint.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/S3AdminEndpoint.java
similarity index 96%
rename from hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/S3AdminEndpoint.java
rename to hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/S3AdminEndpoint.java
index d91b1dea4fcb..278f94d2073b 100644
--- a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/S3AdminEndpoint.java
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/S3AdminEndpoint.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package org.apache.hadoop.ozone.s3secret;
+package org.apache.hadoop.ozone.s3web.s3secret;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/S3SecretAdminFilter.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/S3SecretAdminFilter.java
similarity index 97%
rename from hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/S3SecretAdminFilter.java
rename to hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/S3SecretAdminFilter.java
index 0130f31e9dd3..556f41914f11 100644
--- a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/S3SecretAdminFilter.java
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/S3SecretAdminFilter.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package org.apache.hadoop.ozone.s3secret;
+package org.apache.hadoop.ozone.s3web.s3secret;
import java.io.IOException;
import java.security.Principal;
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/S3SecretConfigKeys.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/S3SecretConfigKeys.java
similarity index 96%
rename from hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/S3SecretConfigKeys.java
rename to hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/S3SecretConfigKeys.java
index ce1070194144..e3067686fec6 100644
--- a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/S3SecretConfigKeys.java
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/S3SecretConfigKeys.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package org.apache.hadoop.ozone.s3secret;
+package org.apache.hadoop.ozone.s3web.s3secret;
/**
* This class contains constants for configuration keys used
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/S3SecretEnabled.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/S3SecretEnabled.java
similarity index 96%
rename from hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/S3SecretEnabled.java
rename to hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/S3SecretEnabled.java
index c0a5084079f6..35ce0a656c11 100644
--- a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/S3SecretEnabled.java
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/S3SecretEnabled.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package org.apache.hadoop.ozone.s3secret;
+package org.apache.hadoop.ozone.s3web.s3secret;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/S3SecretEnabledEndpointRequestFilter.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/S3SecretEnabledEndpointRequestFilter.java
similarity index 92%
rename from hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/S3SecretEnabledEndpointRequestFilter.java
rename to hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/S3SecretEnabledEndpointRequestFilter.java
index 96d9f4c54258..465ecc3e1261 100644
--- a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/S3SecretEnabledEndpointRequestFilter.java
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/S3SecretEnabledEndpointRequestFilter.java
@@ -15,9 +15,9 @@
* limitations under the License.
*/
-package org.apache.hadoop.ozone.s3secret;
+package org.apache.hadoop.ozone.s3web.s3secret;
-import static org.apache.hadoop.ozone.s3secret.S3SecretConfigKeys.OZONE_S3G_SECRET_HTTP_ENABLED_KEY;
+import static org.apache.hadoop.ozone.s3web.s3secret.S3SecretConfigKeys.OZONE_S3G_SECRET_HTTP_ENABLED_KEY;
import java.io.IOException;
import javax.inject.Inject;
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/S3SecretEndpointBase.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/S3SecretEndpointBase.java
similarity index 98%
rename from hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/S3SecretEndpointBase.java
rename to hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/S3SecretEndpointBase.java
index 9a1a6af21ea4..d53ee2470b2e 100644
--- a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/S3SecretEndpointBase.java
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/S3SecretEndpointBase.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package org.apache.hadoop.ozone.s3secret;
+package org.apache.hadoop.ozone.s3web.s3secret;
import com.google.common.annotations.VisibleForTesting;
import java.io.IOException;
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/S3SecretManagementEndpoint.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/S3SecretManagementEndpoint.java
similarity index 98%
rename from hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/S3SecretManagementEndpoint.java
rename to hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/S3SecretManagementEndpoint.java
index 648c9d26ed00..f46c34b5761b 100644
--- a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/S3SecretManagementEndpoint.java
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/S3SecretManagementEndpoint.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package org.apache.hadoop.ozone.s3secret;
+package org.apache.hadoop.ozone.s3web.s3secret;
import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
import static javax.ws.rs.core.Response.Status.NOT_FOUND;
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/S3SecretResponse.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/S3SecretResponse.java
similarity index 97%
rename from hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/S3SecretResponse.java
rename to hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/S3SecretResponse.java
index e3fdb4d6fd74..248d2025bc5e 100644
--- a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/S3SecretResponse.java
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/S3SecretResponse.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package org.apache.hadoop.ozone.s3secret;
+package org.apache.hadoop.ozone.s3web.s3secret;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/package-info.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/package-info.java
similarity index 94%
rename from hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/package-info.java
rename to hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/package-info.java
index 438d4aff2b32..a1986a03af42 100644
--- a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3secret/package-info.java
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3secret/package-info.java
@@ -18,4 +18,4 @@
/**
* This package contains the top level generic classes of s3 secret gateway.
*/
-package org.apache.hadoop.ozone.s3secret;
+package org.apache.hadoop.ozone.s3web.s3secret;
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3sts/S3STSConfigKeys.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3sts/S3STSConfigKeys.java
new file mode 100644
index 000000000000..23ee64b2a22b
--- /dev/null
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3sts/S3STSConfigKeys.java
@@ -0,0 +1,34 @@
+/*
+ * 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.hadoop.ozone.s3web.s3sts;
+
+/**
+ * This class contains constants for configuration keys used
+ * in S3 STS endpoint.
+ */
+public final class S3STSConfigKeys {
+ public static final String OZONE_S3G_STS_HTTP_ENABLED_KEY =
+ "ozone.s3g.sts.http.enabled";
+
+ /**
+ * Never constructed.
+ */
+ private S3STSConfigKeys() {
+
+ }
+}
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3sts/S3STSEnabled.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3sts/S3STSEnabled.java
new file mode 100644
index 000000000000..6da6ee4293eb
--- /dev/null
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3sts/S3STSEnabled.java
@@ -0,0 +1,35 @@
+/*
+ * 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.hadoop.ozone.s3web.s3sts;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import javax.ws.rs.NameBinding;
+
+/**
+ * Annotation to disable S3 STS Endpoint.
+ */
+@NameBinding
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface S3STSEnabled {
+}
+
+
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3sts/S3STSEnabledEndpointRequestFilter.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3sts/S3STSEnabledEndpointRequestFilter.java
new file mode 100644
index 000000000000..08d29430e526
--- /dev/null
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3sts/S3STSEnabledEndpointRequestFilter.java
@@ -0,0 +1,64 @@
+/*
+ * 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.hadoop.ozone.s3web.s3sts;
+
+import static org.apache.hadoop.ozone.s3web.s3sts.S3STSConfigKeys.OZONE_S3G_STS_HTTP_ENABLED_KEY;
+
+import java.io.IOException;
+import javax.inject.Inject;
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerRequestFilter;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.Provider;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+
+/**
+ * Filter that disables all endpoints annotated with {@link S3STSEnabled}.
+ * Condition is based on the value of the configuration key
+ * ozone.s3g.s3sts.http.enabled.
+ */
+@S3STSEnabled
+@Provider
+public class S3STSEnabledEndpointRequestFilter implements ContainerRequestFilter {
+ @Inject
+ private OzoneConfiguration ozoneConfiguration;
+
+ @Override
+ public void filter(ContainerRequestContext requestContext) throws IOException {
+ boolean isSTSEnabled = ozoneConfiguration.getBoolean(
+ OZONE_S3G_STS_HTTP_ENABLED_KEY, false);
+ if (!isSTSEnabled) {
+ String errorMessage = "S3 STS endpoint is disabled.";
+ String errorCode = "AccessDenied";
+ String xmlError = "" +
+ "" +
+ "Sender" +
+ "" + errorCode + "" +
+ "" + errorMessage + "" +
+ "" +
+ "" + requestContext.getHeaderString("x-amz-request-id") + "" +
+ "";
+
+ requestContext.abortWith(Response.status(Response.Status.BAD_REQUEST)
+ .entity(xmlError)
+ .type(MediaType.APPLICATION_XML_TYPE)
+ .build());
+ }
+ }
+}
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3sts/S3STSEndpoint.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3sts/S3STSEndpoint.java
new file mode 100644
index 000000000000..f9d38a521991
--- /dev/null
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3sts/S3STSEndpoint.java
@@ -0,0 +1,298 @@
+/*
+ * 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.hadoop.ozone.s3web.s3sts;
+
+import java.io.IOException;
+import java.time.Instant;
+import java.time.format.DateTimeFormatter;
+import java.util.Base64;
+import java.util.Random;
+import java.util.UUID;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.apache.hadoop.ozone.s3.exception.OS3Exception;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * AWS STS (Security Token Service) compatible endpoint for Ozone S3 Gateway.
+ *
+ * This endpoint provides temporary security credentials compatible with
+ * AWS STS API, exposed on the webadmin port (19878) at /sts endpoint.
+ *
+ * Currently supports only AssumeRole operation. Other STS operations will
+ * return appropriate error responses.
+ *
+ * @see AWS STS API Reference
+ */
+@Path("/")
+@S3STSEnabled
+public class S3STSEndpoint extends S3STSEndpointBase {
+
+ private static final Logger LOG = LoggerFactory.getLogger(S3STSEndpoint.class);
+
+ // STS API constants
+ private static final String STS_ACTION_PARAM = "Action";
+ private static final String ASSUME_ROLE_ACTION = "AssumeRole";
+ private static final String ROLE_ARN_PARAM = "RoleArn";
+ private static final String ROLE_DURATION_SECONDS_PARAM = "DurationSeconds";
+ private static final String GET_SESSION_TOKEN_ACTION = "GetSessionToken";
+ private static final String ASSUME_ROLE_WITH_SAML_ACTION = "AssumeRoleWithSAML";
+ private static final String ASSUME_ROLE_WITH_WEB_IDENTITY_ACTION = "AssumeRoleWithWebIdentity";
+ private static final String GET_CALLER_IDENTITY_ACTION = "GetCallerIdentity";
+ private static final String DECODE_AUTHORIZATION_MESSAGE_ACTION = "DecodeAuthorizationMessage";
+ private static final String GET_ACCESS_KEY_INFO_ACTION = "GetAccessKeyInfo";
+
+ // Default token duration (in seconds) - AWS default is 3600 (1 hour)
+ private static final int DEFAULT_DURATION_SECONDS = 3600;
+ private static final int MAX_DURATION_SECONDS = 43200; // 12 hours
+ private static final int MIN_DURATION_SECONDS = 900; // 15 minutes
+
+ /**
+ * STS endpoint that handles GET requests with query parameters.
+ * AWS STS supports both GET and POST requests.
+ *
+ * @param action The STS action to perform (AssumeRole, GetSessionToken, etc.)
+ * @param roleArn The ARN of the role to assume (for AssumeRole)
+ * @param roleSessionName Session name for the role (for AssumeRole)
+ * @param durationSeconds Duration of the token validity in seconds
+ * @param version AWS STS API version (should be "2011-06-15")
+ * @return Response containing STS response XML or error
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_XML)
+ public Response get(
+ @QueryParam("Action") String action,
+ @QueryParam("RoleArn") String roleArn,
+ @QueryParam("RoleSessionName") String roleSessionName,
+ @QueryParam("DurationSeconds") Integer durationSeconds,
+ @QueryParam("Version") String version) throws OS3Exception {
+
+ return handleSTSRequest(action, roleArn, roleSessionName, durationSeconds, version);
+ }
+
+ /**
+ * STS endpoint that handles POST requests with form data.
+ * AWS STS typically uses POST requests with form-encoded parameters.
+ *
+ * @param action The STS action to perform
+ * @param roleArn The ARN of the role to assume
+ * @param roleSessionName Session name for the role
+ * @param durationSeconds Duration of the token validity
+ * @param version AWS STS API version
+ * @return Response containing STS response XML or error
+ */
+ @POST
+ @Produces(MediaType.APPLICATION_XML)
+ public Response post(
+ @FormParam("Action") String action,
+ @FormParam("RoleArn") String roleArn,
+ @FormParam("RoleSessionName") String roleSessionName,
+ @FormParam("DurationSeconds") Integer durationSeconds,
+ @FormParam("Version") String version) throws OS3Exception {
+
+ return handleSTSRequest(action, roleArn, roleSessionName, durationSeconds, version);
+ }
+
+ private Response handleSTSRequest(String action, String roleArn, String roleSessionName,
+ Integer durationSeconds, String version) throws OS3Exception {
+ try {
+ if (action == null) {
+ return Response.status(Response.Status.BAD_REQUEST)
+ .entity("Missing required parameter: " + STS_ACTION_PARAM)
+ .build();
+ }
+ int duration;
+ try {
+ duration = validateDuration(durationSeconds);
+ } catch (IllegalArgumentException e) {
+ return Response.status(Response.Status.BAD_REQUEST)
+ .entity(e.getMessage())
+ .build();
+ }
+
+ switch (action) {
+ case ASSUME_ROLE_ACTION:
+ return handleAssumeRole(roleArn, roleSessionName, duration);
+ // These operations are not supported yet
+ case GET_SESSION_TOKEN_ACTION:
+ case ASSUME_ROLE_WITH_SAML_ACTION:
+ case ASSUME_ROLE_WITH_WEB_IDENTITY_ACTION:
+ case GET_CALLER_IDENTITY_ACTION:
+ case DECODE_AUTHORIZATION_MESSAGE_ACTION:
+ case GET_ACCESS_KEY_INFO_ACTION:
+ return Response.status(Response.Status.NOT_IMPLEMENTED)
+ .entity("Operation " + action + " is not supported yet.")
+ .build();
+ default:
+ return Response.status(Response.Status.BAD_REQUEST)
+ .entity("Unsupported Action: " + action)
+ .build();
+ }
+ } catch (OS3Exception s3e) {
+ // Handle known S3 exceptions
+ LOG.error("S3 Error during STS request: {}", s3e.toXml());
+ throw s3e;
+ } catch (Exception ex) {
+ LOG.error("Unexpected error during STS request", ex);
+ return Response.serverError().build();
+ }
+ }
+
+ private int validateDuration(Integer durationSeconds) throws IllegalArgumentException, OS3Exception {
+ if (durationSeconds == null) {
+ return DEFAULT_DURATION_SECONDS;
+ }
+
+ if (durationSeconds < MIN_DURATION_SECONDS || durationSeconds > MAX_DURATION_SECONDS) {
+ throw new IllegalArgumentException(
+ "Invalid Value: " + ROLE_DURATION_SECONDS_PARAM + " must be between " + MIN_DURATION_SECONDS +
+ " and " + MAX_DURATION_SECONDS + " seconds");
+ }
+
+ return durationSeconds;
+ }
+
+ private Response handleAssumeRole(String roleArn, String roleSessionName, int duration)
+ throws IOException, OS3Exception {
+ // Validate required parameters for AssumeRole. RoleArn is required to pass the
+ if (roleArn == null || roleArn.isEmpty()) {
+ return Response.status(Response.Status.BAD_REQUEST)
+ .entity("Missing required parameter: " + ROLE_ARN_PARAM)
+ .build();
+ }
+
+ if (roleSessionName == null || roleSessionName.isEmpty()) {
+ return Response.status(Response.Status.BAD_REQUEST)
+ .entity("Missing required parameter: RoleSessionName")
+ .build();
+ }
+
+ // Validate role session name format (AWS requirements)
+ if (!isValidRoleSessionName(roleSessionName)) {
+ return Response.status(Response.Status.BAD_REQUEST)
+ .entity("Invalid RoleSessionName: must be 2-64 characters long and " +
+ "contain only alphanumeric characters, +, =, ,, ., @, -")
+ .build();
+ }
+ // TODO: Add a validation if a user is not an admin but still allowed to call AssumeRole
+ // TODO: Convert roleArn to a valid Ozone ACL
+ // TODO: Validate requested ACLs
+ // TODO: Create a new S3 credentials for this role session
+ // TODO: Add validated ACLs for the new credentials
+ // TODO: How do we handle expired credentials? We don't support renewal?
+
+ // Generate AssumeRole response
+ String responseXml = generateAssumeRoleResponse(roleArn, roleSessionName, duration);
+
+ return Response.ok(responseXml)
+ .header("Content-Type", "text/xml")
+ .build();
+ }
+
+ // TODO: implement private List toOzoneAcls(String roleArn) to convert roleArn to Ozone ACLs
+ // TODO: implement private List checkAclSubset(List requestedAcls) to validate requested ACLs
+
+ private boolean isValidRoleSessionName(String roleSessionName) {
+ if (roleSessionName.length() < 2 || roleSessionName.length() > 64) {
+ return false;
+ }
+
+ // AWS allows: alphanumeric, +, =, ,, ., @, -
+ return roleSessionName.matches("[a-zA-Z0-9+=,.@\\-]+");
+ }
+
+ // TODO: replace mock implementation with actual logic to generate new credentials
+ private String generateAssumeRoleResponse(String roleArn, String roleSessionName, int duration) {
+ // Generate realistic-looking temporary credentials
+ String accessKeyId = "ASIA" + generateRandomAlphanumeric(16); // AWS temp keys start with ASIA
+ String secretAccessKey = generateRandomBase64(40);
+ String sessionToken = generateSessionToken();
+ String expiration = getExpirationTime(duration);
+
+ // Generate AssumedRoleId (format: AROLEID:RoleSessionName)
+ String roleId = "AROA" + generateRandomAlphanumeric(16);
+ String assumedRoleId = roleId + ":" + roleSessionName;
+
+ String requestId = UUID.randomUUID().toString();
+
+ return String.format(
+ "%n" +
+ "%n" +
+ " %n" +
+ " %n" +
+ " %s%n" +
+ " %s%n" +
+ " %s%n" +
+ " %s%n" +
+ " %n" +
+ " %n" +
+ " %s%n" +
+ " %s%n" +
+ " %n" +
+ " %n" +
+ " %n" +
+ " %s%n" +
+ " %n" +
+ "",
+ accessKeyId, secretAccessKey, sessionToken, expiration,
+ assumedRoleId, roleArn, requestId);
+ }
+
+ // Helper methods to generate random alphanumeric and base64 strings for mock credentials.
+ // TODO: these should be replaced with actual credential generation logic.
+ private String generateRandomAlphanumeric(int length) {
+ String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ StringBuilder sb = new StringBuilder();
+ Random random = new Random();
+ for (int i = 0; i < length; i++) {
+ sb.append(chars.charAt(random.nextInt(chars.length())));
+ }
+ return sb.toString();
+ }
+
+ private String generateRandomBase64(int length) {
+ String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ StringBuilder sb = new StringBuilder();
+ Random random = new Random();
+ for (int i = 0; i < length; i++) {
+ sb.append(chars.charAt((random.nextInt(chars.length()))));
+ }
+ return sb.toString();
+ }
+
+ private String generateSessionToken() {
+ byte[] tokenBytes = new byte[128];
+ Random random = new Random();
+ for (int i = 0; i < tokenBytes.length; i++) {
+ tokenBytes[i] = (byte) random.nextInt(256);
+ }
+ return Base64.getEncoder().encodeToString(tokenBytes);
+ }
+
+ private String getExpirationTime(int durationSeconds) {
+ Instant expiration = Instant.now().plusSeconds(durationSeconds);
+ return DateTimeFormatter.ISO_INSTANT.format(expiration);
+ }
+}
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3sts/S3STSEndpointBase.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3sts/S3STSEndpointBase.java
new file mode 100644
index 000000000000..7e80973e1507
--- /dev/null
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3sts/S3STSEndpointBase.java
@@ -0,0 +1,97 @@
+/*
+ * 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.hadoop.ozone.s3web.s3sts;
+
+import com.google.common.annotations.VisibleForTesting;
+import java.util.Map;
+import javax.inject.Inject;
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.core.Context;
+import org.apache.hadoop.ozone.audit.AuditAction;
+import org.apache.hadoop.ozone.audit.AuditEventStatus;
+import org.apache.hadoop.ozone.audit.AuditLogger;
+import org.apache.hadoop.ozone.audit.AuditLoggerType;
+import org.apache.hadoop.ozone.audit.AuditMessage;
+import org.apache.hadoop.ozone.audit.Auditor;
+import org.apache.hadoop.ozone.client.OzoneClient;
+import org.apache.hadoop.ozone.s3.util.AuditUtils;
+
+/**
+ * Base class for STS endpoints.
+ */
+public class S3STSEndpointBase implements Auditor {
+
+ @Context
+ private ContainerRequestContext context;
+
+ @Inject
+ private OzoneClient client;
+
+ protected static final AuditLogger AUDIT =
+ new AuditLogger(AuditLoggerType.S3GLOGGER);
+
+ protected String userNameFromRequest() {
+ return context.getSecurityContext().getUserPrincipal().getName();
+ }
+
+ private AuditMessage.Builder auditMessageBaseBuilder(AuditAction op,
+ Map auditMap) {
+ AuditMessage.Builder builder = new AuditMessage.Builder()
+ .forOperation(op)
+ .withParams(auditMap);
+ if (context != null) {
+ builder.atIp(AuditUtils.getClientIpAddress(context));
+ }
+ return builder;
+ }
+
+ @Override
+ public AuditMessage buildAuditMessageForSuccess(AuditAction op,
+ Map auditMap) {
+ AuditMessage.Builder builder = auditMessageBaseBuilder(op, auditMap)
+ .withResult(AuditEventStatus.SUCCESS);
+ return builder.build();
+ }
+
+ @Override
+ public AuditMessage buildAuditMessageForFailure(AuditAction op,
+ Map auditMap, Throwable throwable) {
+ AuditMessage.Builder builder = auditMessageBaseBuilder(op, auditMap)
+ .withResult(AuditEventStatus.FAILURE)
+ .withException(throwable);
+ return builder.build();
+ }
+
+ public OzoneClient getClient() {
+ return client;
+ }
+
+ @VisibleForTesting
+ public void setClient(OzoneClient ozoneClient) {
+ this.client = ozoneClient;
+ }
+
+ @VisibleForTesting
+ public void setContext(ContainerRequestContext context) {
+ this.context = context;
+ }
+
+ protected Map getAuditParameters() {
+ return AuditUtils.getAuditParameters(context);
+ }
+}
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3sts/package-info.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3sts/package-info.java
new file mode 100644
index 000000000000..f629c2497866
--- /dev/null
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3web/s3sts/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/**
+ * This package contains the AWS STS (Security Token Service) compatible API for S3 Gateway.
+ */
+package org.apache.hadoop.ozone.s3web.s3sts;
diff --git a/hadoop-ozone/s3gateway/src/main/resources/webapps/s3g-web/WEB-INF/web.xml b/hadoop-ozone/s3gateway/src/main/resources/webapps/s3g-web/WEB-INF/web.xml
index 092c8a41af5a..41c547dd9be0 100644
--- a/hadoop-ozone/s3gateway/src/main/resources/webapps/s3g-web/WEB-INF/web.xml
+++ b/hadoop-ozone/s3gateway/src/main/resources/webapps/s3g-web/WEB-INF/web.xml
@@ -15,18 +15,22 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
- secret
+ web
org.glassfish.jersey.servlet.ServletContainer
javax.ws.rs.Application
- org.apache.hadoop.ozone.s3secret.Application
+ org.apache.hadoop.ozone.s3web.Application
1
- secret
+ web
/secret/*
+
+ web
+ /sts/*
+
org.jboss.weld.environment.servlet.Listener
diff --git a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3secret/TestSecretGenerate.java b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3web/s3secret/TestSecretGenerate.java
similarity index 99%
rename from hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3secret/TestSecretGenerate.java
rename to hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3web/s3secret/TestSecretGenerate.java
index 72879c45f835..0fcc47f1fc7f 100644
--- a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3secret/TestSecretGenerate.java
+++ b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3web/s3secret/TestSecretGenerate.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package org.apache.hadoop.ozone.s3secret;
+package org.apache.hadoop.ozone.s3web.s3secret;
import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
import static org.junit.jupiter.api.Assertions.assertEquals;
diff --git a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3secret/TestSecretRevoke.java b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3web/s3secret/TestSecretRevoke.java
similarity index 98%
rename from hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3secret/TestSecretRevoke.java
rename to hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3web/s3secret/TestSecretRevoke.java
index 500cb7272dd6..aae9ea3fb6a3 100644
--- a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3secret/TestSecretRevoke.java
+++ b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3web/s3secret/TestSecretRevoke.java
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package org.apache.hadoop.ozone.s3secret;
+package org.apache.hadoop.ozone.s3web.s3secret;
import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
import static javax.ws.rs.core.Response.Status.NOT_FOUND;
diff --git a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3web/s3sts/TestSTS.java b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3web/s3sts/TestSTS.java
new file mode 100644
index 000000000000..6fab567f6d0c
--- /dev/null
+++ b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3web/s3sts/TestSTS.java
@@ -0,0 +1,109 @@
+/*
+ * 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.hadoop.ozone.s3web.s3sts;
+
+import static org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_S3_ADMINISTRATORS;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ozone.client.OzoneClient;
+import org.apache.hadoop.ozone.client.OzoneClientStub;
+import org.apache.hadoop.ozone.s3.OzoneConfigurationHolder;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+
+/**
+ * Test for S3 STS endpoint.
+ */
+public class TestSTS {
+ private OzoneClient clientStub;
+ private S3STSEndpoint endpoint;
+ private HttpHeaders httpHeaders;
+
+ @Mock
+ private ContainerRequestContext context;
+
+ @BeforeEach
+ public void setup() throws Exception {
+ OzoneConfiguration config = new OzoneConfiguration();
+ config.set(OZONE_S3_ADMINISTRATORS, "test-user");
+ OzoneConfigurationHolder.setConfiguration(config);
+ clientStub = new OzoneClientStub();
+ httpHeaders = mock(HttpHeaders.class);
+ when(httpHeaders.getHeaderString("Authorization"))
+ .thenReturn("AWS4-HMAC-SHA256 Credential=test-user/20240709/us-east-1/s3/aws4_request, "
+ + "SignedHeaders=host;x-amz-date, Signature=some-signature");
+ endpoint = new S3STSEndpoint();
+ endpoint.setClient(clientStub);
+ endpoint.setContext(context);
+ }
+
+ @Test
+ public void testStsAssumeRoleInSecureCluster() throws Exception {
+ String roleArn = "arn:aws:iam::123456789012:role/test-role";
+ String roleSessionName = "test-session";
+
+ Response response = endpoint.get(
+ "AssumeRole", roleArn, roleSessionName, 3600, "2011-06-15");
+
+ assertEquals(200, response.getStatus());
+
+ String responseXml = (String) response.getEntity();
+ assertNotNull(responseXml);
+ assertTrue(responseXml.contains("AssumeRoleResponse"));
+ assertTrue(responseXml.contains("AccessKeyId"));
+ assertTrue(responseXml.contains("SecretAccessKey"));
+ assertTrue(responseXml.contains("SessionToken"));
+ assertTrue(responseXml.contains("AssumedRoleUser"));
+ assertTrue(responseXml.contains(roleArn));
+ }
+
+ @Test
+ public void testStsInvalidDuration() throws Exception {
+ String roleArn = "arn:aws:iam::123456789012:role/test-role";
+ String roleSessionName = "test-session";
+
+ Response response = endpoint.get(
+ "AssumeRole", roleArn, roleSessionName, -1, "2011-06-15");
+
+ assertEquals(400, response.getStatus());
+ String errorMessage = (String) response.getEntity();
+ assertTrue(errorMessage.contains("Invalid Value: DurationSeconds"));
+ }
+
+ @Test
+ public void testStsUnsupportedAction() throws Exception {
+ String roleArn = "arn:aws:iam::123456789012:role/test-role";
+ String roleSessionName = "test-session";
+
+ Response response = endpoint.get(
+ "UnsupportedAction", roleArn, roleSessionName, 3600, "2011-06-15");
+
+ assertEquals(400, response.getStatus());
+ String errorMessage = (String) response.getEntity();
+ assertTrue(errorMessage.contains("Unsupported Action"));
+ }
+}