/** * POST TITLE: Pomerium for Access Control in Java * * Complete implementation of Pomerium for identity-aware access proxy in Java applications */ import com.fasterxml.jackson.databind.ObjectMapper; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.security.Keys; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import java.io.*; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; import java.nio.file.*; import java.security.Key; import java.util.*; import java.util.concurrent.*; public class PomeriumJavaIntegration { /** * Pomerium JWT Verifier and Validator */ public static class PomeriumJWTVerifier { private final String sharedSecret; private final String issuer; private final Key signingKey; private final ObjectMapper objectMapper; private final HttpClient httpClient; public PomeriumJWTVerifier(String sharedSecret, String issuer) { this.sharedSecret = sharedSecret; this.issuer = issuer; this.signingKey = Keys.hmacShaKeyFor(sharedSecret.getBytes()); this.objectMapper = new ObjectMapper(); this.httpClient = HttpClient.newBuilder() .version(HttpClient.Version.HTTP_1_1) .build(); } /** * Pomerium JWT Claims */ public static class PomeriumClaims { private String iss; private String sub; private String aud; private String exp; private String iat; private String jti; private String email; private List<String> groups; private Map<String, Object> user; private Map<String, Object> claims; // Getters and setters public String getIss() { return iss; } public void setIss(String iss) { this.iss = iss; } public String getSub() { return sub; } public void setSub(String sub) { this.sub = sub; } public String getAud() { return aud; } public void setAud(String aud) { this.aud = aud; } public String getExp() { return exp; } public void setExp(String exp) { this.exp = exp; } public String getIat() { return iat; } public void setIat(String iat) { this.iat = iat; } public String getJti() { return jti; } public void setJti(String jti) { this.jti = jti; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public List<String> getGroups() { return groups; } public void setGroups(List<String> groups) { this.groups = groups; } public Map<String, Object> getUser() { return user; } public void setUser(Map<String, Object> user) { this.user = user; } public Map<String, Object> getClaims() { return claims; } public void setClaims(Map<String, Object> claims) { this.claims = claims; } } /** * Verify and parse Pomerium JWT from header */ public PomeriumClaims verifyJWT(String jwtToken) { try { Claims claims = Jwts.parserBuilder() .setSigningKey(signingKey) .build() .parseClaimsJws(jwtToken) .getBody(); // Validate issuer if (!issuer.equals(claims.getIssuer())) { throw new SecurityException("Invalid JWT issuer"); } // Convert to PomeriumClaims PomeriumClaims pomeriumClaims = new PomeriumClaims(); pomeriumClaims.setIss(claims.getIssuer()); pomeriumClaims.setSub(claims.getSubject()); pomeriumClaims.setAud(claims.getAudience()); pomeriumClaims.setExp(claims.getExpiration().toString()); pomeriumClaims.setIat(claims.getIssuedAt().toString()); pomeriumClaims.setJti(claims.getId()); // Extract custom claims pomeriumClaims.setEmail(claims.get("email", String.class)); @SuppressWarnings("unchecked") List<String> groups = claims.get("groups", List.class); pomeriumClaims.setGroups(groups); @SuppressWarnings("unchecked") Map<String, Object> user = claims.get("user", Map.class); pomeriumClaims.setUser(user); return pomeriumClaims; } catch (Exception e) { throw new SecurityException("JWT verification failed: " + e.getMessage(), e); } } /** * Extract JWT from Authorization header */ public String extractJWTFromHeader(String authorizationHeader) { if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) { throw new SecurityException("Missing or invalid Authorization header"); } return authorizationHeader.substring(7); // Remove "Bearer " prefix } /** * Validate user access based on Pomerium claims */ public boolean validateAccess(PomeriumClaims claims, String requiredRole, Set<String> allowedGroups) { // Check if user has required role if (requiredRole != null) { @SuppressWarnings("unchecked") List<String> roles = (List<String>) claims.getUser().get("roles"); if (roles == null || !roles.contains(requiredRole)) { return false; } } // Check if user is in allowed groups if (allowedGroups != null && !allowedGroups.isEmpty()) { if (claims.getGroups() == null || claims.getGroups().stream().noneMatch(allowedGroups::contains)) { return false; } } return true; } /** * Get user identity from claims */ public UserIdentity extractUserIdentity(PomeriumClaims claims) { UserIdentity identity = new UserIdentity(); identity.setUserId(claims.getSub()); identity.setEmail(claims.getEmail()); identity.setGroups(claims.getGroups()); identity.setClaims(claims.getClaims()); // Extract additional user info if (claims.getUser() != null) { identity.setName((String) claims.getUser().get("name")); identity.setPicture((String) claims.getUser().get("picture")); } return identity; } } /** * User Identity Representation */ public static class UserIdentity { private String userId; private String email; private String name; private String picture; private List<String> groups; private Map<String, Object> claims; // Getters and setters public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPicture() { return picture; } public void setPicture(String picture) { this.picture = picture; } public List<String> getGroups() { return groups; } public void setGroups(List<String> groups) { this.groups = groups; } public Map<String, Object> getClaims() { return claims; } public void setClaims(Map<String, Object> claims) { this.claims = claims; } } /** * Pomerium Access Control Filter */ public static class PomeriumAccessFilter { private final PomeriumJWTVerifier jwtVerifier; private final Map<String, AccessPolicy> routePolicies; private final Set<String> publicRoutes; public PomeriumAccessFilter(PomeriumJWTVerifier jwtVerifier) { this.jwtVerifier = jwtVerifier; this.routePolicies = new ConcurrentHashMap<>(); this.publicRoutes = ConcurrentHashMap.newKeySet(); initializeDefaultPolicies(); } /** * Access Policy Configuration */ public static class AccessPolicy { private String route; private String requiredRole; private Set<String> allowedGroups; private Set<String> allowedEmails; private Set<String> allowedDomains; private boolean publicAccess; public AccessPolicy(String route) { this.route = route; this.allowedGroups = new HashSet<>(); this.allowedEmails = new HashSet<>(); this.allowedDomains = new HashSet<>(); } // Builder methods public AccessPolicy withRequiredRole(String role) { this.requiredRole = role; return this; } public AccessPolicy withAllowedGroups(Set<String> groups) { this.allowedGroups = groups; return this; } public AccessPolicy withAllowedEmails(Set<String> emails) { this.allowedEmails = emails; return this; } public AccessPolicy withAllowedDomains(Set<String> domains) { this.allowedDomains = domains; return this; } public AccessPolicy withPublicAccess(boolean publicAccess) { this.publicAccess = publicAccess; return this; } // Getters public String getRoute() { return route; } public String getRequiredRole() { return requiredRole; } public Set<String> getAllowedGroups() { return allowedGroups; } public Set<String> getAllowedEmails() { return allowedEmails; } public Set<String> getAllowedDomains() { return allowedDomains; } public boolean isPublicAccess() { return publicAccess; } } /** * Filter request and validate access */ public boolean filterRequest(String requestPath, String authorizationHeader) { // Check if route is public if (isPublicRoute(requestPath)) { return true; } // Extract and verify JWT try { String jwtToken = jwtVerifier.extractJWTFromHeader(authorizationHeader); PomeriumJWTVerifier.PomeriumClaims claims = jwtVerifier.verifyJWT(jwtToken); // Get access policy for route AccessPolicy policy = getAccessPolicy(requestPath); if (policy == null) { // Default deny if no policy defined return false; } // Validate access based on policy return validateAccessWithPolicy(claims, policy); } catch (Exception e) { System.err.println("❌ Access validation failed: " + e.getMessage()); return false; } } /** * Filter request and set Spring Security context */ public boolean filterAndAuthenticate(String requestPath, String authorizationHeader) { if (!filterRequest(requestPath, authorizationHeader)) { return false; } try { String jwtToken = jwtVerifier.extractJWTFromHeader(authorizationHeader); PomeriumJWTVerifier.PomeriumClaims claims = jwtVerifier.verifyJWT(jwtToken); UserIdentity userIdentity = jwtVerifier.extractUserIdentity(claims); // Set Spring Security context setSecurityContext(userIdentity); return true; } catch (Exception e) { System.err.println("❌ Authentication failed: " + e.getMessage()); return false; } } private boolean isPublicRoute(String requestPath) { return publicRoutes.stream().anyMatch(requestPath::startsWith); } private AccessPolicy getAccessPolicy(String requestPath) { return routePolicies.entrySet().stream() .filter(entry -> requestPath.startsWith(entry.getKey())) .map(Map.Entry::getValue) .findFirst() .orElse(null); } private boolean validateAccessWithPolicy(PomeriumJWTVerifier.PomeriumClaims claims, AccessPolicy policy) { // Check public access if (policy.isPublicAccess()) { return true; } // Check email restrictions if (!policy.getAllowedEmails().isEmpty()) { if (!policy.getAllowedEmails().contains(claims.getEmail())) { return false; } } // Check domain restrictions if (!policy.getAllowedDomains().isEmpty()) { String emailDomain = claims.getEmail().substring(claims.getEmail().indexOf('@') + 1); if (!policy.getAllowedDomains().contains(emailDomain)) { return false; } } // Check role and group access return jwtVerifier.validateAccess(claims, policy.getRequiredRole(), policy.getAllowedGroups()); } private void setSecurityContext(UserIdentity userIdentity) { List<SimpleGrantedAuthority> authorities = new ArrayList<>(); // Add groups as authorities if (userIdentity.getGroups() != null) { userIdentity.getGroups().forEach(group -> authorities.add(new SimpleGrantedAuthority("ROLE_" + group.toUpperCase()))); } // Create authentication token UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( userIdentity, null, authorities ); SecurityContextHolder.getContext().setAuthentication(authentication); } /** * Add access policy for route */ public void addAccessPolicy(AccessPolicy policy) { routePolicies.put(policy.getRoute(), policy); if (policy.isPublicAccess()) { publicRoutes.add(policy.getRoute()); } System.out.println("✅ Added access policy for route: " + policy.getRoute()); } /** * Remove access policy */ public void removeAccessPolicy(String route) { routePolicies.remove(route); publicRoutes.remove(route); System.out.println("🗑️ Removed access policy for route: " + route); } private void initializeDefaultPolicies() { // Public routes addAccessPolicy(new AccessPolicy("/public") .withPublicAccess(true)); addAccessPolicy(new AccessPolicy("/health") .withPublicAccess(true)); addAccessPolicy(new AccessPolicy("/actuator/health") .withPublicAccess(true)); // Admin routes addAccessPolicy(new AccessPolicy("/admin") .withRequiredRole("admin") .withAllowedGroups(Set.of("administrators"))); // API routes addAccessPolicy(new AccessPolicy("/api") .withAllowedGroups(Set.of("developers", "api-users"))); System.out.println("✅ Default access policies initialized"); } } /** * Pomerium Configuration Manager */ public static class PomeriumConfigManager { private final Path configPath; private final ObjectMapper objectMapper; public PomeriumConfigManager(Path configPath) { this.configPath = configPath; this.objectMapper = new ObjectMapper(); } /** * Pomerium Configuration */ public static class PomeriumConfiguration { private String sharedSecret; private String issuer; private String authenticateServiceUrl; private String authorizeServiceUrl; private String databrokerServiceUrl; private Map<String, RouteConfig> routes; private Map<String, PolicyConfig> policies; public PomeriumConfiguration() { this.routes = new HashMap<>(); this.policies = new HashMap<>(); } // Getters and setters public String getSharedSecret() { return sharedSecret; } public void setSharedSecret(String sharedSecret) { this.sharedSecret = sharedSecret; } public String getIssuer() { return issuer; } public void setIssuer(String issuer) { this.issuer = issuer; } public String getAuthenticateServiceUrl() { return authenticateServiceUrl; } public void setAuthenticateServiceUrl(String authenticateServiceUrl) { this.authenticateServiceUrl = authenticateServiceUrl; } public String getAuthorizeServiceUrl() { return authorizeServiceUrl; } public void setAuthorizeServiceUrl(String authorizeServiceUrl) { this.authorizeServiceUrl = authorizeServiceUrl; } public String getDatabrokerServiceUrl() { return databrokerServiceUrl; } public void setDatabrokerServiceUrl(String databrokerServiceUrl) { this.databrokerServiceUrl = databrokerServiceUrl; } public Map<String, RouteConfig> getRoutes() { return routes; } public void setRoutes(Map<String, RouteConfig> routes) { this.routes = routes; } public Map<String, PolicyConfig> getPolicies() { return policies; } public void setPolicies(Map<String, PolicyConfig> policies) { this.policies = policies; } } public static class RouteConfig { private String from; private String to; private List<String> allowedUsers; private List<String> allowedGroups; private List<String> allowedDomains; private boolean passIdentityHeaders = true; private boolean setResponseHeaders = true; // Getters and setters public String getFrom() { return from; } public void setFrom(String from) { this.from = from; } public String getTo() { return to; } public void setTo(String to) { this.to = to; } public List<String> getAllowedUsers() { return allowedUsers; } public void setAllowedUsers(List<String> allowedUsers) { this.allowedUsers = allowedUsers; } public List<String> getAllowedGroups() { return allowedGroups; } public void setAllowedGroups(List<String> allowedGroups) { this.allowedGroups = allowedGroups; } public List<String> getAllowedDomains() { return allowedDomains; } public void setAllowedDomains(List<String> allowedDomains) { this.allowedDomains = allowedDomains; } public boolean isPassIdentityHeaders() { return passIdentityHeaders; } public void setPassIdentityHeaders(boolean passIdentityHeaders) { this.passIdentityHeaders = passIdentityHeaders; } public boolean isSetResponseHeaders() { return setResponseHeaders; } public void setSetResponseHeaders(boolean setResponseHeaders) { this.setResponseHeaders = setResponseHeaders; } } public static class PolicyConfig { private String name; private List<String> allowedUsers; private List<String> allowedGroups; private List<String> allowedDomains; private Map<String, String> headers; // Getters and setters public String getName() { return name; } public void setName(String name) { this.name = name; } public List<String> getAllowedUsers() { return allowedUsers; } public void setAllowedUsers(List<String> allowedUsers) { this.allowedUsers = allowedUsers; } public List<String> getAllowedGroups() { return allowedGroups; } public void setAllowedGroups(List<String> allowedGroups) { this.allowedGroups = allowedGroups; } public List<String> getAllowedDomains() { return allowedDomains; } public void setAllowedDomains(List<String> allowedDomains) { this.allowedDomains = allowedDomains; } public Map<String, String> getHeaders() { return headers; } public void setHeaders(Map<String, String> headers) { this.headers = headers; } } /** * Load configuration from file */ public PomeriumConfiguration loadConfiguration() throws IOException { try { return objectMapper.readValue(configPath.toFile(), PomeriumConfiguration.class); } catch (IOException e) { System.err.println("❌ Failed to load Pomerium configuration: " + e.getMessage()); throw e; } } /** * Save configuration to file */ public void saveConfiguration(PomeriumConfiguration config) throws IOException { try { objectMapper.writerWithDefaultPrettyPrinter() .writeValue(configPath.toFile(), config); System.out.println("✅ Pomerium configuration saved: " + configPath); } catch (IOException e) { System.err.println("❌ Failed to save Pomerium configuration: " + e.getMessage()); throw e; } } /** * Generate sample configuration */ public PomeriumConfiguration generateSampleConfig() { PomeriumConfiguration config = new PomeriumConfiguration(); config.setSharedSecret("your-shared-secret-here"); config.setIssuer("https://authenticate.example.com"); config.setAuthenticateServiceUrl("https://authenticate.example.com"); config.setAuthorizeServiceUrl("https://authorize.example.com"); config.setDatabrokerServiceUrl("https://databroker.example.com"); // Sample routes RouteConfig apiRoute = new RouteConfig(); apiRoute.setFrom("https://api.example.com"); apiRoute.setTo("http://localhost:8080"); apiRoute.setAllowedGroups(Arrays.asList("developers", "api-users")); apiRoute.setAllowedDomains(Arrays.asList("example.com")); config.getRoutes().put("api", apiRoute); RouteConfig adminRoute = new RouteConfig(); adminRoute.setFrom("https://admin.example.com"); adminRoute.setTo("http://localhost:8081"); adminRoute.setAllowedGroups(Arrays.asList("administrators")); adminRoute.setAllowedUsers(Arrays.asList("[email protected]")); config.getRoutes().put("admin", adminRoute); // Sample policies PolicyConfig apiPolicy = new PolicyConfig(); apiPolicy.setName("api-access"); apiPolicy.setAllowedGroups(Arrays.asList("developers", "api-users")); apiPolicy.setHeaders(Map.of("X-API-Version", "v1")); config.getPolicies().put("api-access", apiPolicy); return config; } } /** * Spring Boot Integration */ @Configuration @ConfigurationProperties(prefix = "pomerium") public static class PomeriumProperties { private String sharedSecret; private String issuer; private boolean enabled = true; private String configPath = "./pomerium-config.json"; // Getters and setters public String getSharedSecret() { return sharedSecret; } public void setSharedSecret(String sharedSecret) { this.sharedSecret = sharedSecret; } public String getIssuer() { return issuer; } public void setIssuer(String issuer) { this.issuer = issuer; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public String getConfigPath() { return configPath; } public void setConfigPath(String configPath) { this.configPath = configPath; } } @SpringBootApplication public static class PomeriumIntegrationApplication { @Bean public PomeriumJWTVerifier pomeriumJWTVerifier(PomeriumProperties properties) { return new PomeriumJWTVerifier(properties.getSharedSecret(), properties.getIssuer()); } @Bean public PomeriumAccessFilter pomeriumAccessFilter(PomeriumJWTVerifier jwtVerifier) { return new PomeriumAccessFilter(jwtVerifier); } @Bean public PomeriumConfigManager pomeriumConfigManager(PomeriumProperties properties) { return new PomeriumConfigManager(Paths.get(properties.getConfigPath())); } } /** * Spring Security Configuration */ @Configuration @EnableWebSecurity public static class SecurityConfig { private final PomeriumAccessFilter pomeriumAccessFilter; public SecurityConfig(PomeriumAccessFilter pomeriumAccessFilter) { this.pomeriumAccessFilter = pomeriumAccessFilter; } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(authz -> authz .requestMatchers("/public/**", "/health/**", "/actuator/health").permitAll() .requestMatchers("/admin/**").hasRole("ADMINISTRATORS") .requestMatchers("/api/**").hasAnyRole("DEVELOPERS", "API-USERS") .anyRequest().authenticated() ) .addFilterBefore(new PomeriumAuthenticationFilter(pomeriumAccessFilter), UsernamePasswordAuthenticationFilter.class) .csrf().disable(); // Pomerium handles CSRF return http.build(); } } /** * Custom Authentication Filter */ public static class PomeriumAuthenticationFilter extends OncePerRequestFilter { private final PomeriumAccessFilter pomeriumAccessFilter; public PomeriumAuthenticationFilter(PomeriumAccessFilter pomeriumAccessFilter) { this.pomeriumAccessFilter = pomeriumAccessFilter; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String authorizationHeader = request.getHeader("Authorization"); String requestPath = request.getRequestURI(); try { if (pomeriumAccessFilter.filterAndAuthenticate(requestPath, authorizationHeader)) { filterChain.doFilter(request, response); } else { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.getWriter().write("{\"error\": \"Access denied\"}"); } } catch (Exception e) { response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); response.getWriter().write("{\"error\": \"Authentication error: " + e.getMessage() + "\"}"); } } } @RestController @RequestMapping("/api") public static class SecureApiController { @GetMapping("/user-info") public ResponseEntity<UserIdentity> getUserInfo() { // Get user from Spring Security context Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication != null && authentication.getPrincipal() instanceof UserIdentity) { UserIdentity userIdentity = (UserIdentity) authentication.getPrincipal(); return ResponseEntity.ok(userIdentity); } return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } @GetMapping("/admin/data") public ResponseEntity<Map<String, String>> getAdminData() { // This endpoint requires admin role Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication != null && authentication.getAuthorities().stream() .anyMatch(auth -> auth.getAuthority().equals("ROLE_ADMINISTRATORS"))) { Map<String, String> adminData = Map.of( "message", "Sensitive admin data", "timestamp", new Date().toString() ); return ResponseEntity.ok(adminData); } return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); } @GetMapping("/public/info") public ResponseEntity<Map<String, String>> getPublicInfo() { // Public endpoint - no authentication required Map<String, String> publicInfo = Map.of( "message", "Public information", "timestamp", new Date().toString() ); return ResponseEntity.ok(publicInfo); } } /** * Pomerium Client for Service-to-Service Communication */ public static class PomeriumServiceClient { private final HttpClient httpClient; private final String pomeriumUrl; private final String sharedSecret; public PomeriumServiceClient(String pomeriumUrl, String sharedSecret) { this.pomeriumUrl = pomeriumUrl; this.sharedSecret = sharedSecret; this.httpClient = HttpClient.newBuilder() .version(HttpClient.Version.HTTP_1_1) .build(); } /** * Make authenticated request through Pomerium */ public HttpResponse<String> makeAuthenticatedRequest(String serviceUrl, String method, String body) throws IOException, InterruptedException { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(pomeriumUrl + serviceUrl)) .header("Authorization", "Bearer " + sharedSecret) .header("Content-Type", "application/json") .method(method, body != null ? HttpRequest.BodyPublishers.ofString(body) : HttpRequest.BodyPublishers.noBody()) .build(); return httpClient.send(request, HttpResponse.BodyHandlers.ofString()); } /** * Validate service ticket */ public boolean validateServiceTicket(String ticket) { try { // Implementation would validate service ticket with Pomerium return true; // Simplified } catch (Exception e) { return false; } } } /** * Demo and Usage Examples */ public static void main(String[] args) { System.out.println("🛡️ Pomerium for Access Control in Java"); System.out.println("=====================================\n"); try { // Demo 1: JWT Verification System.out.println("1. 🔐 JWT Verification Setup"); PomeriumJWTVerifier jwtVerifier = new PomeriumJWTVerifier( "your-shared-secret-key-here-at-least-32-chars", "https://authenticate.example.com" ); System.out.println(" JWT Verifier initialized"); // Demo 2: Access Control Filter System.out.println("\n2. 🚦 Access Control Filter"); PomeriumAccessFilter accessFilter = new PomeriumAccessFilter(jwtVerifier); // Add custom policies accessFilter.addAccessPolicy( new PomeriumAccessFilter.AccessPolicy("/api/sensitive") .withRequiredRole("sensitive-data-access") .withAllowedGroups(Set.of("data-scientists", "analysts")) ); System.out.println(" Access filter with policies initialized"); // Demo 3: Configuration Management System.out.println("\n3. ⚙️ Configuration Management"); Path tempConfig = Files.createTempFile("pomerium-config", ".json"); PomeriumConfigManager configManager = new PomeriumConfigManager(tempConfig); PomeriumConfigManager.PomeriumConfiguration sampleConfig = configManager.generateSampleConfig(); configManager.saveConfiguration(sampleConfig); System.out.println(" Sample configuration generated"); // Demo 4: Spring Security Integration System.out.println("\n4. 🌱 Spring Security Integration"); System.out.println(" - Automatic JWT validation"); System.out.println(" - Role-based access control"); System.out.println(" - User identity propagation"); System.out.println(" - Public and protected routes"); // Demo 5: Service Client System.out.println("\n5. 🔗 Service-to-Service Communication"); PomeriumServiceClient serviceClient = new PomeriumServiceClient( "https://pomerium.example.com", "service-shared-secret" ); System.out.println(" Service client for authenticated requests"); // Cleanup Files.deleteIfExists(tempConfig); System.out.println("\n✅ Pomerium Java Integration Demo Completed"); System.out.println("\n📚 Key Features:"); System.out.println(" - JWT-based authentication and authorization"); System.out.println(" - Identity-aware access proxy integration"); System.out.println(" - Role-based and group-based access control"); System.out.println(" - Spring Security integration"); System.out.println(" - Service-to-service authentication"); System.out.println(" - Dynamic access policies"); System.out.println(" - Zero-trust security model"); } catch (Exception e) { System.err.println("❌ Demo failed: " + e.getMessage()); e.printStackTrace(); } } } Maven Dependencies
<!-- pom.xml --> <dependencies> <!-- JWT Handling --> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency> <!-- Spring Boot --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.7.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> <version>2.7.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> <version>2.7.0</version> </dependency> <!-- JSON Processing --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.14.2</version> </dependency> <!-- HTTP Client --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.3.20</version> </dependency> </dependencies>
Configuration Examples
application.yml
pomerium: enabled: true shared-secret: ${POMERIUM_SHARED_SECRET:your-shared-secret-here} issuer: https://authenticate.example.com config-path: ./config/pomerium.json spring: security: oauth2: resourceserver: jwt: issuer-uri: https://authenticate.example.com logging: level: com.example.pomerium: DEBUG pomerium.json Configuration
{ "shared_secret": "your-shared-secret-here", "issuer": "https://authenticate.example.com", "authenticate_service_url": "https://authenticate.example.com", "authorize_service_url": "https://authorize.example.com", "databroker_service_url": "https://databroker.example.com", "routes": { "api-service": { "from": "https://api.example.com", "to": "http://localhost:8080", "allowed_users": ["[email protected]"], "allowed_groups": ["developers", "api-users"], "allowed_domains": ["example.com"], "pass_identity_headers": true }, "admin-service": { "from": "https://admin.example.com", "to": "http://localhost:8081", "allowed_groups": ["administrators"], "pass_identity_headers": true } }, "policies": { "api-access": { "name": "api-access", "allowed_groups": ["developers", "api-users"], "headers": { "X-API-Version": "v1" } } } } Usage Examples
// Initialize Pomerium components PomeriumJWTVerifier jwtVerifier = new PomeriumJWTVerifier( "your-shared-secret", "https://authenticate.example.com" ); PomeriumAccessFilter accessFilter = new PomeriumAccessFilter(jwtVerifier); // Add custom access policies accessFilter.addAccessPolicy( new PomeriumAccessFilter.AccessPolicy("/api/sensitive-data") .withRequiredRole("data-access") .withAllowedGroups(Set.of("data-scientists", "analysts")) .withAllowedDomains(Set.of("example.com")) ); // Use in Spring Security configuration @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http, PomeriumAccessFilter pomeriumFilter) throws Exception { http .authorizeHttpRequests(authz -> authz .requestMatchers("/public/**").permitAll() .requestMatchers("/admin/**").hasRole("ADMINISTRATORS") .anyRequest().authenticated() ) .addFilterBefore(new PomeriumAuthenticationFilter(pomeriumFilter), UsernamePasswordAuthenticationFilter.class); return http.build(); } } // Secure REST endpoints @RestController public class SecureController { @GetMapping("/api/user-info") public ResponseEntity<UserIdentity> getUserInfo() { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); UserIdentity user = (UserIdentity) auth.getPrincipal(); return ResponseEntity.ok(user); } @GetMapping("/admin/dashboard") @PreAuthorize("hasRole('ADMINISTRATORS')") public ResponseEntity<Map<String, String>> getAdminDashboard() { // Only users with ADMINISTRATORS role can access return ResponseEntity.ok(Map.of("data", "sensitive admin data")); } } Pomerium Headers
When Pomerium proxies requests, it adds several headers:
X-Pomerium-Jwt-Assertion: The JWT tokenX-Pomerium-Claim-*: Various user claims (email, groups, etc.)Authorization: Bearer token for service-to-service communication
This Pomerium implementation provides:
- JWT Verification with proper signature validation
- Access Control Policies with role-based and group-based rules
- Spring Security Integration for seamless adoption
- User Identity Propagation through security context
- Service-to-Service Authentication with shared secrets
- Dynamic Policy Management for flexible access control
- Zero-Trust Security Model implementation
- Configuration Management for multi-environment support
- Health Monitoring and error handling
- **REST
Java Logistics, Shipping Integration & Enterprise Inventory Automation (Tracking, ERP, RFID & Billing Systems)
https://macronepal.com/blog/aftership-tracking-in-java-enterprise-package-visibility/
Explains how to integrate AfterShip tracking services into Java applications to provide real-time shipment visibility, delivery status updates, and centralized tracking across multiple courier services.
https://macronepal.com/blog/shipping-integration-using-fedex-api-with-java-for-logistics-automation/
Explains how to integrate the FedEx API into Java systems to automate shipping tasks such as creating shipments, calculating delivery costs, generating shipping labels, and tracking packages.
https://macronepal.com/blog/shipping-and-logistics-integrating-ups-apis-with-java-applications/
Explains UPS API integration in Java to enable automated shipping operations including rate calculation, shipment scheduling, tracking, and delivery confirmation management.
https://macronepal.com/blog/generating-and-reading-qr-codes-for-products-in-java/
Explains how Java applications generate and read QR codes for product identification, tracking, and authentication, supporting faster inventory handling and product verification processes.
https://macronepal.com/blog/designing-a-robust-pick-and-pack-workflow-in-java/
Explains how to design an efficient pick-and-pack workflow in Java warehouse systems, covering order processing, item selection, packaging steps, and logistics preparation to improve fulfillment efficiency.
https://macronepal.com/blog/rfid-inventory-management-system-in-java-a-complete-guide/
Explains how RFID technology integrates with Java applications to automate inventory tracking, reduce manual errors, and enable real-time stock monitoring in warehouses and retail environments.
https://macronepal.com/blog/erp-integration-with-odoo-in-java/
Explains how Java applications connect with Odoo ERP systems to synchronize inventory, orders, customer records, and financial data across enterprise systems.
https://macronepal.com/blog/automated-invoice-generation-creating-professional-excel-invoices-with-apache-poi-in-java/
Explains how to automatically generate professional Excel invoices in Java using Apache POI, enabling structured billing documents and automated financial record creation.
https://macronepal.com/blog/enterprise-financial-integration-using-quickbooks-api-in-java-applications/
Explains QuickBooks API integration in Java to automate financial workflows such as invoice management, payment tracking, accounting synchronization, and financial reporting.