/modules/vertx-swagger-router/src/main/java/com/github/phiz71/vertx/swagger/router/auth/SwaggerAuthHandlerFactory.java

https://github.com/phiz71/vertx-swagger · Java · 142 lines · 112 code · 25 blank · 5 comment · 17 complexity · 1c6e817c11422216200395c66cb08060 MD5 · raw file

  1. package com.github.phiz71.vertx.swagger.router.auth;
  2. import com.github.phiz71.vertx.swagger.router.SwaggerRouter;
  3. import com.github.phiz71.vertx.swagger.router.auth.ApiKeyAuthHandler.Location;
  4. import io.swagger.models.auth.ApiKeyAuthDefinition;
  5. import io.swagger.models.auth.SecuritySchemeDefinition;
  6. import io.vertx.core.AsyncResult;
  7. import io.vertx.core.Handler;
  8. import io.vertx.core.json.JsonObject;
  9. import io.vertx.core.logging.Logger;
  10. import io.vertx.core.logging.LoggerFactory;
  11. import io.vertx.ext.auth.AuthProvider;
  12. import io.vertx.ext.auth.User;
  13. import io.vertx.ext.web.RoutingContext;
  14. import io.vertx.ext.web.handler.AuthHandler;
  15. import io.vertx.ext.web.handler.BasicAuthHandler;
  16. import java.util.*;
  17. import java.util.concurrent.ConcurrentHashMap;
  18. import static com.github.phiz71.vertx.swagger.router.auth.AuthProviderRegistry.getAuthProviderFactory;
  19. public class SwaggerAuthHandlerFactory {
  20. private static Logger vertxLogger = LoggerFactory.getLogger(SwaggerAuthHandlerFactory.class);
  21. private final Map<String, AuthHandler> authHandlers = new ConcurrentHashMap<>();
  22. private final Map<String, SecuritySchemeDefinition> securitySchemes;
  23. public static SwaggerAuthHandlerFactory create(Map<String, SecuritySchemeDefinition> securitySchemes) {
  24. return new SwaggerAuthHandlerFactory(securitySchemes);
  25. }
  26. private SwaggerAuthHandlerFactory(Map<String, SecuritySchemeDefinition> securitySchemes) {
  27. this.securitySchemes = securitySchemes;
  28. }
  29. private AuthHandler getAuthHandler(String name) {
  30. AuthHandler authHandler = this.authHandlers.get(name);
  31. if (authHandler != null) {
  32. return authHandler;
  33. }
  34. AuthProvider authProvider = getAuthProviderFactory().getAuthProviderByName(name);
  35. if (authProvider == null) {
  36. return null;
  37. }
  38. SecuritySchemeDefinition securityScheme = this.securitySchemes.get(name);
  39. if(securityScheme != null) {
  40. switch (securityScheme.getType()) {
  41. case "apiKey":
  42. ApiKeyAuthDefinition apiKeyAuthDefinition = (ApiKeyAuthDefinition) securityScheme;
  43. Location apiKeyLocation = Location.valueOf(apiKeyAuthDefinition.getIn().name());
  44. authHandler = ApiKeyAuthHandler.create(authProvider, apiKeyLocation, apiKeyAuthDefinition.getName());
  45. break;
  46. case "basic":
  47. authHandler = BasicAuthHandler.create(authProvider);
  48. break;
  49. case "oauth2":
  50. vertxLogger.warn("OAuth2 authentication has not been implemented yet!");
  51. break;
  52. default:
  53. vertxLogger.warn("SecurityScheme is not authorized : " + securityScheme.getType());
  54. break;
  55. }
  56. if (authHandler != null) {
  57. this.authHandlers.put(name, authHandler);
  58. }
  59. } else {
  60. vertxLogger.warn("No securityScheme definition in swagger file for auth provider: " + name);
  61. }
  62. return authHandler;
  63. }
  64. public AuthHandler createAuthHandler(final List<Map<String, List<String>>> security) {
  65. return new AuthHandler() {
  66. private Set<String> authorities = new HashSet<>();
  67. public AuthHandler addAuthority(String authority) {
  68. this.authorities.add(authority);
  69. return this;
  70. }
  71. public AuthHandler addAuthorities(Set<String> authorities) {
  72. this.authorities.addAll(authorities);
  73. return this;
  74. }
  75. @Override
  76. public void parseCredentials(RoutingContext routingContext, Handler<AsyncResult<JsonObject>> handler) {
  77. }
  78. @Override
  79. public void authorize(User user, Handler<AsyncResult<Void>> handler) {
  80. }
  81. private void handle(InterceptableRoutingContext context, int orLevelIndex, int andLevelIndex) {
  82. // reset context
  83. context.clearUser();
  84. context.setNextCallback(null);
  85. context.setFailedCallback(null);
  86. // prepare routing next of failure behaviours
  87. if (andLevelIndex < security.get(orLevelIndex).size() - 1) {
  88. context.setNextCallback(() -> handle(context, orLevelIndex, andLevelIndex + 1));
  89. }
  90. if (orLevelIndex < security.size() - 1) {
  91. context.setFailedCallback(() -> handle(context, orLevelIndex + 1, 0));
  92. }
  93. // navigate to the auth provider at given orIndex and andIndex and call it.
  94. // if it fails, the context will call the next auth handler at the OR level, or fail or no more are available.
  95. // if it succeeds, the context will call the next auth handler at the AND level, or call the next route handler if no more are available.
  96. Map<String, List<String>> orSecurityIdentifiers = security.get(orLevelIndex);
  97. if (!orSecurityIdentifiers.isEmpty()) {
  98. List<String> andSecurityIdentifiers = new ArrayList<>(orSecurityIdentifiers.keySet());
  99. String securityIdentifier = andSecurityIdentifiers.get(andLevelIndex);
  100. AuthHandler handler = SwaggerAuthHandlerFactory.this.getAuthHandler(securityIdentifier);
  101. if (handler != null) {
  102. context.put(SwaggerRouter.AUTH_PROVIDER_NAME_HEADER_KEY, securityIdentifier);
  103. handler.addAuthorities(this.authorities).handle(context);
  104. } else {
  105. context.fail(401);
  106. }
  107. } else {
  108. context.fail(401);
  109. }
  110. }
  111. @Override
  112. public void handle(RoutingContext context) {
  113. handle(new InterceptableRoutingContext(context), 0, 0);
  114. }
  115. };
  116. }
  117. }