/**
* 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.