This is an automated email from the ASF dual-hosted git repository.

yasith pushed a commit to branch feat/spring-module-reorg
in repository https://gitbox.apache.org/repos/asf/airavata.git

commit 764c18810d264dbd9c12b541e8fa933664ec1aa4
Author: yasithdev <[email protected]>
AuthorDate: Fri Mar 27 22:26:55 2026 -0500

    feat: create airavata-grpc-server with centralized gRPC auth interceptor
---
 airavata-grpc-server/pom.xml                       | 122 +++++++++++++++++++++
 .../grpc/server/AiravataGrpcServerConfig.java      |  35 ++++++
 .../grpc/server/config/GrpcAuthInterceptor.java    | 104 ++++++++++++++++++
 pom.xml                                            |   1 +
 4 files changed, 262 insertions(+)

diff --git a/airavata-grpc-server/pom.xml b/airavata-grpc-server/pom.xml
new file mode 100644
index 0000000000..6852ae093d
--- /dev/null
+++ b/airavata-grpc-server/pom.xml
@@ -0,0 +1,122 @@
+<!--
+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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.airavata</groupId>
+        <artifactId>airavata</artifactId>
+        <version>0.21-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>airavata-grpc-server</artifactId>
+    <name>Airavata gRPC Server</name>
+
+    <dependencies>
+        <!-- Project modules -->
+        <dependency>
+            <groupId>org.apache.airavata</groupId>
+            <artifactId>airavata-api</artifactId>
+            <version>${project.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>ch.qos.logback</groupId>
+                    <artifactId>logback-classic</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>ch.qos.logback</groupId>
+                    <artifactId>logback-core</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-log4j12</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.airavata</groupId>
+            <artifactId>agent-service</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.airavata</groupId>
+            <artifactId>research-service</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <!-- gRPC -->
+        <dependency>
+            <groupId>net.devh</groupId>
+            <artifactId>grpc-server-spring-boot-starter</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>ch.qos.logback</groupId>
+                    <artifactId>logback-classic</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>ch.qos.logback</groupId>
+                    <artifactId>logback-core</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <!-- Spring Boot -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-jpa</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-logging</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-actuator</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-logging</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <!-- Database -->
+        <dependency>
+            <groupId>org.mariadb.jdbc</groupId>
+            <artifactId>mariadb-java-client</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <release>17</release>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git 
a/airavata-grpc-server/src/main/java/org/apache/airavata/grpc/server/AiravataGrpcServerConfig.java
 
b/airavata-grpc-server/src/main/java/org/apache/airavata/grpc/server/AiravataGrpcServerConfig.java
new file mode 100644
index 0000000000..6bdc8c2fae
--- /dev/null
+++ 
b/airavata-grpc-server/src/main/java/org/apache/airavata/grpc/server/AiravataGrpcServerConfig.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.airavata.grpc.server;
+
+import org.apache.airavata.agent.connection.service.config.AgentServiceConfig;
+import org.apache.airavata.common.config.ConditionalOnServer;
+import org.apache.airavata.research.service.config.ResearchServiceConfig;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+
+@Configuration
+@ConditionalOnServer("grpc")
+@Import({
+    AgentServiceConfig.class,
+    ResearchServiceConfig.class
+})
+public class AiravataGrpcServerConfig {
+}
diff --git 
a/airavata-grpc-server/src/main/java/org/apache/airavata/grpc/server/config/GrpcAuthInterceptor.java
 
b/airavata-grpc-server/src/main/java/org/apache/airavata/grpc/server/config/GrpcAuthInterceptor.java
new file mode 100644
index 0000000000..142a3e78d0
--- /dev/null
+++ 
b/airavata-grpc-server/src/main/java/org/apache/airavata/grpc/server/config/GrpcAuthInterceptor.java
@@ -0,0 +1,104 @@
+/**
+*
+* 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.airavata.grpc.server.config;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.grpc.ForwardingServerCallListener;
+import io.grpc.Metadata;
+import io.grpc.ServerCall;
+import io.grpc.ServerCallHandler;
+import io.grpc.ServerInterceptor;
+import io.grpc.Status;
+import net.devh.boot.grpc.server.interceptor.GrpcGlobalServerInterceptor;
+import org.apache.airavata.common.security.UserContext;
+import org.apache.airavata.model.security.AuthzToken;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@GrpcGlobalServerInterceptor
+public class GrpcAuthInterceptor implements ServerInterceptor {
+
+    private static final Logger log = 
LoggerFactory.getLogger(GrpcAuthInterceptor.class);
+    private static final ObjectMapper objectMapper = new ObjectMapper();
+
+    private static final Metadata.Key<String> AUTHORIZATION_KEY =
+            Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER);
+    private static final Metadata.Key<String> X_CLAIMS_KEY =
+            Metadata.Key.of("x-claims", Metadata.ASCII_STRING_MARSHALLER);
+
+    @Override
+    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
+            ServerCall<ReqT, RespT> call,
+            Metadata headers,
+            ServerCallHandler<ReqT, RespT> next) {
+
+        String authHeader = headers.get(AUTHORIZATION_KEY);
+        String accessToken = null;
+        if (authHeader != null && authHeader.startsWith("Bearer ")) {
+            accessToken = authHeader.substring(7);
+        }
+
+        if (accessToken == null) {
+            call.close(Status.UNAUTHENTICATED.withDescription("Missing 
authorization metadata"), new Metadata());
+            return new ServerCall.Listener<>() {};
+        }
+
+        AuthzToken authzToken = new AuthzToken(accessToken);
+
+        Map<String, String> claimsMap = new HashMap<>();
+        String claimsHeader = headers.get(X_CLAIMS_KEY);
+        if (claimsHeader != null && !claimsHeader.isBlank()) {
+            try {
+                claimsMap = objectMapper.readValue(claimsHeader, new 
TypeReference<Map<String, String>>() {});
+            } catch (Exception e) {
+                log.warn("Failed to parse x-claims metadata: {}", 
e.getMessage());
+            }
+        }
+
+        authzToken.setClaimsMap(claimsMap);
+        UserContext.setAuthzToken(authzToken);
+
+        ServerCall.Listener<ReqT> delegate = next.startCall(call, headers);
+
+        return new 
ForwardingServerCallListener.SimpleForwardingServerCallListener<>(delegate) {
+            @Override
+            public void onComplete() {
+                try {
+                    super.onComplete();
+                } finally {
+                    UserContext.clear();
+                }
+            }
+
+            @Override
+            public void onCancel() {
+                try {
+                    super.onCancel();
+                } finally {
+                    UserContext.clear();
+                }
+            }
+        };
+    }
+}
diff --git a/pom.xml b/pom.xml
index d202121e86..ffee99715e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -75,6 +75,7 @@ under the License.
         <module>modules/agent-framework/agent-service</module>
         <module>modules/research-framework/research-service</module>
         <module>airavata-rest-server</module>
+        <module>airavata-grpc-server</module>
     </modules>
 
     <properties>

Reply via email to