This site is in English. Use your browser's built-in translate feature to read it in your language.

Authentication Pattern

Overview

The Authentication pattern is a fundamental security mechanism in enterprise integration architectures that verifies the identity of users, services, and systems attempting to access protected resources. Like a security checkpoint at a building entrance that verifies identity documents, authentication serves as the first line of defense in establishing trust and ensuring that only legitimate entities can interact with integration services. This pattern encompasses various methods of identity verification, from simple username/password combinations to sophisticated multi-factor authentication and biometric systems, forming the foundation upon which all other security measures are built.

Theoretical Foundation

The Authentication pattern is grounded in identity verification theory and cryptographic security principles, specifically addressing the challenge of entity identification in distributed systems. The pattern incorporates concepts from public key infrastructure (PKI), cryptographic protocols, and identity management systems to provide secure, scalable, and reliable mechanisms for verifying the authenticity of entities requesting access to system resources.

Core Principles

1. Identity Verification

Authentication establishes and validates identity through multiple mechanisms: - Something you know - passwords, PINs, security questions, or passphrases - Something you are - biometric characteristics like fingerprints, facial recognition, or voice patterns - Something you have - physical tokens, smart cards, mobile devices, or hardware security modules - Somewhere you are - geographic location, network location, or device characteristics

2. Multi-Factor Authentication (MFA)

Combining multiple authentication factors for enhanced security: - Two-factor authentication (2FA) - combining two different authentication factors - Risk-based authentication - adjusting authentication requirements based on risk assessment - Adaptive authentication - dynamically changing authentication methods based on context - Step-up authentication - requiring additional authentication for sensitive operations

3. Credential Management

Secure handling of authentication credentials: - Password policies - enforcing strong password requirements and rotation schedules - Credential storage - secure storage using hashing, salting, and encryption - Credential transmission - protecting credentials during network transmission - Credential lifecycle - managing creation, updates, expiration, and revocation

4. Session Management

Managing authenticated sessions securely: - Session establishment - creating secure sessions after successful authentication - Session tokens - generating and managing secure session identifiers - Session timeout - automatically terminating inactive sessions - Session termination - providing secure logout and session cleanup

Why Authentication is Essential in Integration Architecture

1. Security Foundation

Authentication provides the fundamental security layer: - Identity verification - ensuring only legitimate users and systems can access resources - Trust establishment - creating a foundation of trust for subsequent security decisions - Access control enablement - providing verified identity for authorization decisions - Audit trail creation - establishing accountability through verified identity records

2. Regulatory Compliance

For meeting compliance requirements: - Data protection regulations - ensuring only authorized entities access personal data - Financial regulations - verifying identity for financial transactions and data access - Healthcare compliance - protecting patient data through strong authentication - Industry standards - meeting authentication requirements for specific industries

3. Risk Mitigation

Reducing security risks through proper authentication: - Unauthorized access prevention - blocking illegitimate access attempts - Data breach protection - preventing unauthorized data exposure - System integrity - maintaining system security through verified access - Business continuity - ensuring operations continue securely

4. Integration Security

For secure system-to-system communication: - Service authentication - verifying the identity of calling services - API security - protecting API endpoints through authentication - Message integrity - ensuring messages come from verified sources - Trust boundaries - establishing secure communication between different systems

Benefits in Integration Contexts

1. Enhanced Security Posture

2. Operational Excellence

3. Business Value

4. Integration Enablement

Integration Architecture Applications

1. Enterprise Application Integration

Authentication in enterprise systems provides: - Service-to-service authentication - verifying identity of calling services - User authentication federation - sharing authentication across multiple systems - Legacy system integration - adding authentication to existing systems - Cross-domain authentication - enabling authentication across organizational boundaries

2. API Management and Microservices

In modern distributed architectures: - API gateway authentication - centralizing authentication for microservices - Service mesh security - implementing authentication between microservices - OAuth 2.0 flows - securing API access through standardized authentication - JWT token validation - verifying authentication tokens in distributed systems

3. Cloud and Hybrid Environments

For cloud integrations: - Identity federation - sharing authentication across cloud and on-premises systems - SAML authentication - enabling enterprise single sign-on to cloud services - Cloud service authentication - verifying identity when accessing cloud APIs - Multi-cloud authentication - managing authentication across multiple cloud providers

4. Partner and B2B Integration

For external integrations: - Mutual authentication - verifying identity of both parties in B2B communications - Certificate-based authentication - using digital certificates for partner verification - API key management - managing authentication keys for external partners - Federated identity - sharing authentication across organizational boundaries

Implementation Patterns

1. Basic Username/Password Authentication

// Basic authentication implementation with security best practices
@Service
public class BasicAuthenticationService {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private AuthenticationAttemptService attemptService;

    public AuthenticationResult authenticate(String username, String password) {
        // Check for account lockout
        if (attemptService.isBlocked(username)) {
            log.warn("Authentication attempt for blocked user: {}", username);
            return AuthenticationResult.blocked("Account temporarily locked");
        }

        try {
            // Retrieve user details
            UserDetails user = userRepository.findByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException("User not found"));

            // Verify password
            if (passwordEncoder.matches(password, user.getPasswordHash())) {
                // Reset failed attempts on successful login
                attemptService.resetFailedAttempts(username);

                // Create authentication session
                AuthenticationSession session = createAuthenticationSession(user);

                log.info("Successful authentication for user: {}", username);

                return AuthenticationResult.success(user, session);
            } else {
                // Record failed attempt
                attemptService.recordFailedAttempt(username);

                log.warn("Failed authentication for user: {}", username);
                return AuthenticationResult.failure("Invalid credentials");
            }

        } catch (Exception e) {
            log.error("Authentication error for user: " + username, e);
            return AuthenticationResult.error("Authentication service unavailable");
        }
    }

    private AuthenticationSession createAuthenticationSession(UserDetails user) {
        String sessionToken = generateSecureToken();
        Instant expirationTime = Instant.now().plus(Duration.ofHours(8));

        AuthenticationSession session = AuthenticationSession.builder()
            .sessionToken(sessionToken)
            .userId(user.getId())
            .username(user.getUsername())
            .roles(user.getRoles())
            .createdAt(Instant.now())
            .expiresAt(expirationTime)
            .lastAccessedAt(Instant.now())
            .build();

        // Store session in secure session store
        sessionStore.save(session);

        return session;
    }

    private String generateSecureToken() {
        SecureRandom random = new SecureRandom();
        byte[] tokenBytes = new byte[32];
        random.nextBytes(tokenBytes);
        return Base64.getUrlEncoder().withoutPadding().encodeToString(tokenBytes);
    }
}

@Service
public class AuthenticationAttemptService {

    private final Map<String, AttemptCounter> attemptCache = new ConcurrentHashMap<>();
    private final int maxFailedAttempts = 5;
    private final Duration lockoutDuration = Duration.ofMinutes(30);

    public boolean isBlocked(String username) {
        AttemptCounter counter = attemptCache.get(username);
        if (counter == null) {
            return false;
        }

        if (counter.getFailedAttempts() >= maxFailedAttempts) {
            if (Instant.now().isBefore(counter.getLockoutUntil())) {
                return true;
            } else {
                // Lockout period expired, reset counter
                attemptCache.remove(username);
                return false;
            }
        }

        return false;
    }

    public void recordFailedAttempt(String username) {
        AttemptCounter counter = attemptCache.computeIfAbsent(username, 
            k -> new AttemptCounter());

        counter.incrementFailedAttempts();

        if (counter.getFailedAttempts() >= maxFailedAttempts) {
            counter.setLockoutUntil(Instant.now().plus(lockoutDuration));
            log.warn("User {} locked out after {} failed attempts", username, maxFailedAttempts);
        }
    }

    public void resetFailedAttempts(String username) {
        attemptCache.remove(username);
    }
}

2. Multi-Factor Authentication (MFA)

// Multi-factor authentication implementation
@Service
public class MultiFactorAuthenticationService {

    @Autowired
    private TOTPService totpService;

    @Autowired
    private SMSService smsService;

    @Autowired
    private EmailService emailService;

    @Autowired
    private DeviceService deviceService;

    public MFAChallenge initiateAuthentication(String username, String password) {
        // First factor: username/password
        AuthenticationResult primaryAuth = basicAuthenticationService.authenticate(username, password);

        if (!primaryAuth.isSuccess()) {
            return MFAChallenge.failed(primaryAuth.getMessage());
        }

        UserDetails user = primaryAuth.getUser();

        // Determine required second factors
        List<MFAMethod> availableMethods = getAvailableMFAMethods(user);

        if (availableMethods.isEmpty()) {
            // No MFA required, complete authentication
            return MFAChallenge.completed(primaryAuth.getSession());
        }

        // Create MFA challenge
        String challengeId = generateChallengeId();
        MFAChallenge challenge = MFAChallenge.builder()
            .challengeId(challengeId)
            .userId(user.getId())
            .availableMethods(availableMethods)
            .createdAt(Instant.now())
            .expiresAt(Instant.now().plus(Duration.ofMinutes(5)))
            .build();

        // Store challenge
        challengeStore.save(challenge);

        // Send challenges based on available methods
        sendMFAChallenges(user, availableMethods, challengeId);

        return challenge;
    }

    public AuthenticationResult completeMFA(String challengeId, MFAResponse response) {
        MFAChallenge challenge = challengeStore.findById(challengeId)
            .orElseThrow(() -> new IllegalArgumentException("Invalid challenge ID"));

        if (challenge.isExpired()) {
            challengeStore.delete(challengeId);
            return AuthenticationResult.failure("MFA challenge expired");
        }

        boolean isValid = false;

        switch (response.getMethod()) {
            case TOTP:
                isValid = totpService.validateTOTP(challenge.getUserId(), response.getToken());
                break;

            case SMS:
                isValid = smsService.validateSMSCode(challengeId, response.getToken());
                break;

            case EMAIL:
                isValid = emailService.validateEmailCode(challengeId, response.getToken());
                break;

            case PUSH:
                isValid = pushService.validatePushResponse(challengeId, response.getToken());
                break;

            default:
                return AuthenticationResult.failure("Unsupported MFA method");
        }

        if (isValid) {
            // Complete authentication
            UserDetails user = userRepository.findById(challenge.getUserId()).orElseThrow();
            AuthenticationSession session = createAuthenticationSession(user);

            // Clean up challenge
            challengeStore.delete(challengeId);

            // Record successful MFA
            auditService.recordMFASuccess(user.getUsername(), response.getMethod());

            return AuthenticationResult.success(user, session);
        } else {
            // Record failed attempt
            challenge.incrementFailedAttempts();

            if (challenge.getFailedAttempts() >= 3) {
                challengeStore.delete(challengeId);
                auditService.recordMFAFailure(challenge.getUserId(), response.getMethod(), "Max attempts exceeded");
                return AuthenticationResult.failure("Maximum MFA attempts exceeded");
            } else {
                challengeStore.save(challenge);
                return AuthenticationResult.failure("Invalid MFA token");
            }
        }
    }

    private void sendMFAChallenges(UserDetails user, List<MFAMethod> methods, String challengeId) {
        for (MFAMethod method : methods) {
            switch (method) {
                case SMS:
                    String smsCode = generateSMSCode();
                    smsService.sendSMSCode(user.getPhoneNumber(), smsCode, challengeId);
                    break;

                case EMAIL:
                    String emailCode = generateEmailCode();
                    emailService.sendEmailCode(user.getEmail(), emailCode, challengeId);
                    break;

                case PUSH:
                    pushService.sendPushNotification(user.getDeviceTokens(), challengeId);
                    break;

                case TOTP:
                    // No action needed, user will use their TOTP app
                    break;
            }
        }
    }
}

@Service
public class TOTPService {

    private final TOTPAlgorithm totpAlgorithm = new TOTPAlgorithm();

    public boolean validateTOTP(String userId, String token) {
        UserTOTPSecret secret = totpSecretRepository.findByUserId(userId)
            .orElseThrow(() -> new IllegalStateException("TOTP not configured for user"));

        // Validate current time window
        long currentTimeStep = System.currentTimeMillis() / 30000; // 30-second windows

        // Check current window and adjacent windows for clock skew tolerance
        for (int i = -1; i <= 1; i++) {
            String expectedToken = totpAlgorithm.generateTOTP(
                secret.getSecretKey(), 
                currentTimeStep + i
            );

            if (token.equals(expectedToken)) {
                // Prevent replay attacks
                if (secret.getLastUsedTimeStep() != null && 
                    currentTimeStep + i <= secret.getLastUsedTimeStep()) {
                    return false; // Token already used
                }

                // Update last used time step
                secret.setLastUsedTimeStep(currentTimeStep + i);
                totpSecretRepository.save(secret);

                return true;
            }
        }

        return false;
    }

    public TOTPSetupResult setupTOTP(String userId) {
        // Generate secret key
        SecureRandom random = new SecureRandom();
        byte[] secretBytes = new byte[20]; // 160-bit secret
        random.nextBytes(secretBytes);
        String secretKey = Base32.encode(secretBytes);

        // Create TOTP secret record
        UserTOTPSecret totpSecret = UserTOTPSecret.builder()
            .userId(userId)
            .secretKey(secretKey)
            .createdAt(Instant.now())
            .enabled(false) // Will be enabled after verification
            .build();

        totpSecretRepository.save(totpSecret);

        // Generate QR code for setup
        String issuer = "Integration Service";
        UserDetails user = userRepository.findById(userId).orElseThrow();
        String qrCodeUrl = String.format(
            "otpauth://totp/%s:%s?secret=%s&issuer=%s",
            issuer, user.getUsername(), secretKey, issuer
        );

        return TOTPSetupResult.builder()
            .secretKey(secretKey)
            .qrCodeUrl(qrCodeUrl)
            .backupCodes(generateBackupCodes(userId))
            .build();
    }
}

3. JWT Token Authentication

// JWT token-based authentication for stateless systems
@Service
public class JWTAuthenticationService {

    @Value("${jwt.secret}")
    private String jwtSecret;

    @Value("${jwt.expiration:3600}") // Default 1 hour
    private long jwtExpiration;

    @Value("${jwt.issuer}")
    private String jwtIssuer;

    private final Algorithm algorithm;
    private final JWTVerifier verifier;

    @PostConstruct
    public void initialize() {
        this.algorithm = Algorithm.HMAC256(jwtSecret);
        this.verifier = JWT.require(algorithm)
            .withIssuer(jwtIssuer)
            .build();
    }

    public JWTAuthenticationResult authenticate(String username, String password) {
        // Perform basic authentication
        AuthenticationResult basicAuth = basicAuthenticationService.authenticate(username, password);

        if (!basicAuth.isSuccess()) {
            return JWTAuthenticationResult.failure(basicAuth.getMessage());
        }

        UserDetails user = basicAuth.getUser();

        // Generate JWT token
        String token = generateJWTToken(user);

        // Generate refresh token
        String refreshToken = generateRefreshToken(user);

        return JWTAuthenticationResult.success(token, refreshToken, user);
    }

    public String generateJWTToken(UserDetails user) {
        Instant now = Instant.now();
        Instant expiration = now.plusSeconds(jwtExpiration);

        return JWT.create()
            .withIssuer(jwtIssuer)
            .withSubject(user.getUsername())
            .withIssuedAt(Date.from(now))
            .withExpiresAt(Date.from(expiration))
            .withClaim("userId", user.getId())
            .withClaim("roles", user.getRoles().stream()
                .map(Role::getName)
                .collect(Collectors.toList()))
            .withClaim("permissions", user.getPermissions())
            .withClaim("sessionId", UUID.randomUUID().toString())
            .sign(algorithm);
    }

    public AuthenticationResult validateJWTToken(String token) {
        try {
            DecodedJWT decodedJWT = verifier.verify(token);

            String username = decodedJWT.getSubject();
            String userId = decodedJWT.getClaim("userId").asString();
            List<String> roles = decodedJWT.getClaim("roles").asList(String.class);
            List<String> permissions = decodedJWT.getClaim("permissions").asList(String.class);
            String sessionId = decodedJWT.getClaim("sessionId").asString();

            // Check if token is blacklisted
            if (tokenBlacklistService.isBlacklisted(sessionId)) {
                return AuthenticationResult.failure("Token has been revoked");
            }

            // Create user context from token claims
            UserDetails user = UserDetails.builder()
                .id(userId)
                .username(username)
                .roles(roles.stream().map(Role::new).collect(Collectors.toSet()))
                .permissions(permissions)
                .build();

            return AuthenticationResult.success(user);

        } catch (TokenExpiredException e) {
            return AuthenticationResult.failure("Token has expired");
        } catch (JWTVerificationException e) {
            log.warn("JWT verification failed: {}", e.getMessage());
            return AuthenticationResult.failure("Invalid token");
        }
    }

    public JWTRefreshResult refreshToken(String refreshToken) {
        try {
            // Validate refresh token
            RefreshTokenDetails tokenDetails = refreshTokenService.validateRefreshToken(refreshToken);

            if (tokenDetails.isExpired()) {
                refreshTokenService.revokeRefreshToken(refreshToken);
                return JWTRefreshResult.failure("Refresh token expired");
            }

            // Get user details
            UserDetails user = userRepository.findById(tokenDetails.getUserId()).orElseThrow();

            // Generate new access token
            String newAccessToken = generateJWTToken(user);

            // Optionally rotate refresh token
            String newRefreshToken = null;
            if (shouldRotateRefreshToken()) {
                newRefreshToken = generateRefreshToken(user);
                refreshTokenService.revokeRefreshToken(refreshToken);
            }

            return JWTRefreshResult.success(newAccessToken, newRefreshToken);

        } catch (Exception e) {
            log.error("Refresh token validation failed", e);
            return JWTRefreshResult.failure("Invalid refresh token");
        }
    }

    public void revokeToken(String token) {
        try {
            DecodedJWT decodedJWT = JWT.decode(token);
            String sessionId = decodedJWT.getClaim("sessionId").asString();
            Instant expiration = decodedJWT.getExpiresAt().toInstant();

            // Add to blacklist until expiration
            tokenBlacklistService.blacklistToken(sessionId, expiration);

            log.info("Token revoked for session: {}", sessionId);

        } catch (Exception e) {
            log.error("Failed to revoke token", e);
        }
    }
}

@Service
public class TokenBlacklistService {

    private final RedisTemplate<String, String> redisTemplate;

    public void blacklistToken(String sessionId, Instant expiration) {
        long ttlSeconds = Duration.between(Instant.now(), expiration).getSeconds();
        if (ttlSeconds > 0) {
            redisTemplate.opsForValue().set(
                "blacklist:" + sessionId, 
                "revoked", 
                Duration.ofSeconds(ttlSeconds)
            );
        }
    }

    public boolean isBlacklisted(String sessionId) {
        return redisTemplate.hasKey("blacklist:" + sessionId);
    }
}

4. Certificate-Based Authentication

// Mutual TLS certificate authentication for service-to-service communication
@Service
public class CertificateAuthenticationService {

    @Autowired
    private CertificateValidationService validationService;

    @Autowired
    private CertificateRevocationService revocationService;

    public CertificateAuthenticationResult authenticateClient(X509Certificate clientCertificate) {
        try {
            // Basic certificate validation
            CertificateValidationResult validationResult = validationService.validateCertificate(clientCertificate);

            if (!validationResult.isValid()) {
                return CertificateAuthenticationResult.failure(
                    "Certificate validation failed: " + validationResult.getErrorMessage()
                );
            }

            // Check certificate revocation status
            if (revocationService.isRevoked(clientCertificate)) {
                return CertificateAuthenticationResult.failure("Certificate has been revoked");
            }

            // Extract client identity from certificate
            ClientIdentity identity = extractClientIdentity(clientCertificate);

            // Check if client is authorized
            if (!isClientAuthorized(identity)) {
                return CertificateAuthenticationResult.failure("Client not authorized");
            }

            log.info("Certificate authentication successful for client: {}", identity.getCommonName());

            return CertificateAuthenticationResult.success(identity, clientCertificate);

        } catch (Exception e) {
            log.error("Certificate authentication error", e);
            return CertificateAuthenticationResult.failure("Certificate authentication failed");
        }
    }

    private ClientIdentity extractClientIdentity(X509Certificate certificate) {
        X500Principal principal = certificate.getSubjectX500Principal();
        String dn = principal.getName();

        Map<String, String> attributes = parseDN(dn);

        return ClientIdentity.builder()
            .commonName(attributes.get("CN"))
            .organization(attributes.get("O"))
            .organizationalUnit(attributes.get("OU"))
            .country(attributes.get("C"))
            .serialNumber(certificate.getSerialNumber().toString())
            .issuer(certificate.getIssuerX500Principal().getName())
            .notBefore(certificate.getNotBefore().toInstant())
            .notAfter(certificate.getNotAfter().toInstant())
            .build();
    }

    private Map<String, String> parseDN(String dn) {
        Map<String, String> attributes = new HashMap<>();

        // Parse distinguished name
        String[] parts = dn.split(",");
        for (String part : parts) {
            String[] keyValue = part.trim().split("=", 2);
            if (keyValue.length == 2) {
                attributes.put(keyValue[0].trim(), keyValue[1].trim());
            }
        }

        return attributes;
    }

    private boolean isClientAuthorized(ClientIdentity identity) {
        // Check against authorized client registry
        return authorizedClientService.isAuthorized(identity.getCommonName(), identity.getOrganization());
    }
}

@Service
public class CertificateValidationService {

    @Autowired
    private TrustedCertificateStore trustedStore;

    public CertificateValidationResult validateCertificate(X509Certificate certificate) {
        List<String> errors = new ArrayList<>();

        try {
            // Check certificate validity period
            certificate.checkValidity();

            // Verify certificate chain
            if (!verifyChainOfTrust(certificate)) {
                errors.add("Certificate chain validation failed");
            }

            // Check key usage
            if (!hasRequiredKeyUsage(certificate)) {
                errors.add("Certificate does not have required key usage");
            }

            // Validate certificate signature
            if (!validateSignature(certificate)) {
                errors.add("Certificate signature validation failed");
            }

            // Check certificate policies
            if (!validateCertificatePolicies(certificate)) {
                errors.add("Certificate policies validation failed");
            }

        } catch (CertificateExpiredException e) {
            errors.add("Certificate has expired");
        } catch (CertificateNotYetValidException e) {
            errors.add("Certificate is not yet valid");
        } catch (Exception e) {
            errors.add("Certificate validation error: " + e.getMessage());
        }

        return CertificateValidationResult.builder()
            .isValid(errors.isEmpty())
            .errors(errors)
            .build();
    }

    private boolean verifyChainOfTrust(X509Certificate certificate) {
        try {
            // Build certificate path
            CertPathBuilder pathBuilder = CertPathBuilder.getInstance("PKIX");

            PKIXBuilderParameters params = new PKIXBuilderParameters(
                trustedStore.getTrustedCertificates(), 
                new X509CertSelector()
            );

            params.setRevocationEnabled(false); // Handled separately

            CertPathBuilderResult result = pathBuilder.build(params);

            return result.getCertPath() != null;

        } catch (Exception e) {
            log.warn("Certificate chain validation failed", e);
            return false;
        }
    }
}

Apache Camel Implementation

1. Basic Authentication Route

@Component
public class BasicAuthenticationRoute extends RouteBuilder {

    @Override
    public void configure() throws Exception {
        from("jetty:http://0.0.0.0:8080/api/secure")
            .routeId("basic-authentication-route")
            .process(exchange -> {
                // Extract Authorization header
                String authHeader = exchange.getIn().getHeader("Authorization", String.class);

                if (authHeader == null || !authHeader.startsWith("Basic ")) {
                    throw new UnauthorizedException("Missing or invalid Authorization header");
                }

                // Decode Basic auth credentials
                String encodedCredentials = authHeader.substring(6);
                String credentials = new String(Base64.getDecoder().decode(encodedCredentials));
                String[] parts = credentials.split(":", 2);

                if (parts.length != 2) {
                    throw new UnauthorizedException("Invalid Basic auth format");
                }

                String username = parts[0];
                String password = parts[1];

                // Authenticate user
                AuthenticationResult result = authenticationService.authenticate(username, password);

                if (!result.isSuccess()) {
                    throw new UnauthorizedException("Authentication failed: " + result.getMessage());
                }

                // Set user context in headers
                exchange.getIn().setHeader("authenticated-user", result.getUser().getUsername());
                exchange.getIn().setHeader("user-roles", result.getUser().getRoles());
            })
            .log("User authenticated: ${header.authenticated-user}")
            .to("direct:processSecureRequest");
    }
}

2. JWT Authentication Route

@Component
public class JWTAuthenticationRoute extends RouteBuilder {

    @Override
    public void configure() throws Exception {
        // JWT Authentication Route
        from("jetty:http://0.0.0.0:8080/api/jwt/secure")
            .routeId("jwt-authentication-route")
            .process(exchange -> {
                String authHeader = exchange.getIn().getHeader("Authorization", String.class);

                if (authHeader == null || !authHeader.startsWith("Bearer ")) {
                    throw new UnauthorizedException("Missing or invalid Authorization header");
                }

                String token = authHeader.substring(7);

                AuthenticationResult result = jwtAuthenticationService.validateJWTToken(token);

                if (!result.isSuccess()) {
                    throw new UnauthorizedException("Token validation failed: " + result.getMessage());
                }

                // Set authenticated user context
                exchange.getIn().setHeader("authenticated-user", result.getUser().getUsername());
                exchange.getIn().setHeader("user-id", result.getUser().getId());
                exchange.getIn().setHeader("user-roles", result.getUser().getRoles());
                exchange.getIn().setHeader("user-permissions", result.getUser().getPermissions());
            })
            .log("JWT authenticated user: ${header.authenticated-user}")
            .to("direct:processJWTSecureRequest");

        // JWT Login Route
        from("jetty:http://0.0.0.0:8080/api/jwt/login")
            .routeId("jwt-login-route")
            .process(exchange -> {
                LoginRequest request = exchange.getIn().getBody(LoginRequest.class);

                JWTAuthenticationResult result = jwtAuthenticationService.authenticate(
                    request.getUsername(), 
                    request.getPassword()
                );

                if (result.isSuccess()) {
                    LoginResponse response = LoginResponse.builder()
                        .accessToken(result.getAccessToken())
                        .refreshToken(result.getRefreshToken())
                        .tokenType("Bearer")
                        .expiresIn(3600) // 1 hour
                        .user(result.getUser())
                        .build();

                    exchange.getIn().setBody(response);
                    exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 200);
                } else {
                    ErrorResponse error = ErrorResponse.builder()
                        .error("authentication_failed")
                        .message(result.getMessage())
                        .build();

                    exchange.getIn().setBody(error);
                    exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 401);
                }
            })
            .marshal().json(JsonLibrary.Jackson);
    }
}

3. Multi-Factor Authentication Route

@Component
public class MFAAuthenticationRoute extends RouteBuilder {

    @Override
    public void configure() throws Exception {
        // MFA Challenge Initiation
        from("jetty:http://0.0.0.0:8080/api/auth/mfa/challenge")
            .routeId("mfa-challenge-route")
            .unmarshal().json(JsonLibrary.Jackson, LoginRequest.class)
            .process(exchange -> {
                LoginRequest request = exchange.getIn().getBody(LoginRequest.class);

                MFAChallenge challenge = mfaService.initiateAuthentication(
                    request.getUsername(), 
                    request.getPassword()
                );

                if (challenge.isCompleted()) {
                    // Authentication complete without MFA
                    AuthenticationResponse response = AuthenticationResponse.builder()
                        .success(true)
                        .session(challenge.getSession())
                        .build();

                    exchange.getIn().setBody(response);
                } else if (challenge.isFailed()) {
                    ErrorResponse error = ErrorResponse.builder()
                        .error("authentication_failed")
                        .message(challenge.getMessage())
                        .build();

                    exchange.getIn().setBody(error);
                    exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 401);
                } else {
                    // MFA challenge issued
                    MFAChallengeResponse response = MFAChallengeResponse.builder()
                        .challengeId(challenge.getChallengeId())
                        .availableMethods(challenge.getAvailableMethods())
                        .expiresAt(challenge.getExpiresAt())
                        .message("Multi-factor authentication required")
                        .build();

                    exchange.getIn().setBody(response);
                }
            })
            .marshal().json(JsonLibrary.Jackson);

        // MFA Challenge Completion
        from("jetty:http://0.0.0.0:8080/api/auth/mfa/verify")
            .routeId("mfa-verify-route")
            .unmarshal().json(JsonLibrary.Jackson, MFAVerificationRequest.class)
            .process(exchange -> {
                MFAVerificationRequest request = exchange.getIn().getBody(MFAVerificationRequest.class);

                MFAResponse mfaResponse = MFAResponse.builder()
                    .method(request.getMethod())
                    .token(request.getToken())
                    .build();

                AuthenticationResult result = mfaService.completeMFA(
                    request.getChallengeId(), 
                    mfaResponse
                );

                if (result.isSuccess()) {
                    AuthenticationResponse response = AuthenticationResponse.builder()
                        .success(true)
                        .session(result.getSession())
                        .user(result.getUser())
                        .build();

                    exchange.getIn().setBody(response);
                } else {
                    ErrorResponse error = ErrorResponse.builder()
                        .error("mfa_verification_failed")
                        .message(result.getMessage())
                        .build();

                    exchange.getIn().setBody(error);
                    exchange.getIn().setHeader(Exchange.HTTP_RESPONSE_CODE, 401);
                }
            })
            .marshal().json(JsonLibrary.Jackson);
    }
}

4. Certificate Authentication Route

@Component
public class CertificateAuthenticationRoute extends RouteBuilder {

    @Override
    public void configure() throws Exception {
        // Configure Jetty for mutual TLS
        JettyHttpComponent jetty = getContext().getComponent("jetty", JettyHttpComponent.class);
        jetty.setSslContextParameters(createSSLContextParameters());

        from("jetty:https://0.0.0.0:8443/api/secure/certificate?sslContextParameters=#sslContextParameters")
            .routeId("certificate-authentication-route")
            .process(exchange -> {
                // Extract client certificate from SSL context
                X509Certificate clientCert = extractClientCertificate(exchange);

                if (clientCert == null) {
                    throw new UnauthorizedException("Client certificate required");
                }

                // Authenticate using certificate
                CertificateAuthenticationResult result = certAuthService.authenticateClient(clientCert);

                if (!result.isSuccess()) {
                    throw new UnauthorizedException("Certificate authentication failed: " + result.getMessage());
                }

                // Set client identity in headers
                ClientIdentity identity = result.getClientIdentity();
                exchange.getIn().setHeader("client-cn", identity.getCommonName());
                exchange.getIn().setHeader("client-org", identity.getOrganization());
                exchange.getIn().setHeader("client-serial", identity.getSerialNumber());
            })
            .log("Certificate authenticated client: ${header.client-cn}")
            .to("direct:processCertificateSecureRequest");
    }

    private SSLContextParameters createSSLContextParameters() {
        KeyManagersParameters keyManagers = new KeyManagersParameters();
        keyManagers.setKeyStore(createKeyStoreParameters());

        TrustManagersParameters trustManagers = new TrustManagersParameters();
        trustManagers.setKeyStore(createTrustStoreParameters());

        SSLContextParameters sslContext = new SSLContextParameters();
        sslContext.setKeyManagers(keyManagers);
        sslContext.setTrustManagers(trustManagers);
        sslContext.setClientAuthentication("REQUIRE");

        return sslContext;
    }

    private X509Certificate extractClientCertificate(Exchange exchange) {
        // Extract certificate from HTTP request
        HttpServletRequest request = exchange.getIn(HttpMessage.class).getRequest();
        X509Certificate[] certificates = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");

        return (certificates != null && certificates.length > 0) ? certificates[0] : null;
    }
}

Best Practices

1. Security Implementation

2. Multi-Factor Authentication

3. Token Management

4. Certificate Authentication

5. Error Handling and Security

6. Monitoring and Compliance

The Authentication pattern is fundamental to enterprise integration security, providing the essential identity verification layer that enables all other security measures and ensures that only authorized entities can access protected resources and services.

← Back to All Patterns