예제 #1
0
        /// <summary>
        /// Visits <see cref="OpenApiOAuthFlow"/> and child objects
        /// </summary>
        internal void Walk(OpenApiOAuthFlow oAuthFlow)
        {
            if (oAuthFlow == null)
            {
                return;
            }

            _visitor.Visit(oAuthFlow);
            Walk(oAuthFlow as IOpenApiExtensible);
        }
예제 #2
0
        private void ConfigureSwaggerGen(IServiceCollection services)
        {
            var authCodeFlow = new OpenApiOAuthFlow
            {
                AuthorizationUrl = new Uri($"{ApiHelper.Authority}/connect/authorize"),
                TokenUrl         = new Uri($"{ApiHelper.Authority}/connect/token"),
                Scopes           = new Dictionary <string, string>
                {
                    { ApiHelper.Audience, "Api access" }
                }
            };

            services.AddSwaggerGen(options =>
            {
                // integrate xml comments
                // options.IncludeXmlComments(XmlCommentsFilePath);

                // Set the comments path for the Swagger JSON and UI.
                // var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                // var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
                // c.IncludeXmlComments(xmlPath);

                // Define the OAuth2.0 scheme that's in use (i.e. Implicit Flow)
                options.OperationFilter <AuthorizeCheckOperationFilter>();
                options.AddSecurityDefinition(
                    ApiInfo.SchemeOauth2,
                    new OpenApiSecurityScheme
                {
                    Type  = SecuritySchemeType.OAuth2,
                    Flows = new OpenApiOAuthFlows
                    {
                        AuthorizationCode = authCodeFlow
                    }
                });
                options.AddSecurityRequirement(
                    new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference
                            {
                                Type = ReferenceType.SecurityScheme,
                                Id   = ApiInfo.SchemeOauth2
                            }
                        },
                        new[]
                        {
                            ApiHelper.Audience
                        }
                    }
                });
            });
        }
        public static OpenApiOAuthFlow LoadOAuthFlow(ParseNode node)
        {
            var mapNode = node.CheckMapNode("OAuthFlow");

            var oauthFlow = new OpenApiOAuthFlow();

            foreach (var property in mapNode)
            {
                property.ParseField(oauthFlow, _oAuthFlowFixedFileds, _oAuthFlowPatternFields);
            }

            return(oauthFlow);
        }
예제 #4
0
        internal OpenApiOAuthFlow ToOpenApi()
        {
            var item = new OpenApiOAuthFlow()
            {
                AuthorizationUrl = string.IsNullOrEmpty(this.AuthorizationUrl) ? null : new Uri(this.AuthorizationUrl),
                TokenUrl         = string.IsNullOrEmpty(this.TokenUrl) ? null : new Uri(this.TokenUrl),
                RefreshUrl       = string.IsNullOrEmpty(this.RefreshUrl) ? null : new Uri(this.RefreshUrl),
                Scopes           = this.Scopes,
                Extensions       = this.Extensions
            };

            return(item);
        }
예제 #5
0
        public void Configure(SwaggerGenOptions options)
        {
            if (!env.IsDevelopment())
            {
                return;
            }

            var authority        = $"{apiOptions.Authorization.Instance}/{apiOptions.Authorization.TenantId}";
            var authorizationUrl = $"{authority}/oauth2/v2.0/authorize";
            var tokenUrl         = $"{authority}/oauth2/v2.0/token";
            var authFlow         = new OpenApiOAuthFlow
            {
                TokenUrl         = new Uri(tokenUrl),
                AuthorizationUrl = new Uri(authorizationUrl),
                Scopes           = new Dictionary <string, string>
                {
                    { $"{apiOptions.Authorization.Audience}/.default", "Default" },
                },
            };

            options.AddSecurityDefinition(
                SecuritySchemeType.OAuth2.ToString(),
                new OpenApiSecurityScheme
            {
                Type  = SecuritySchemeType.OAuth2,
                Flows = new OpenApiOAuthFlows
                {
                    Implicit          = authFlow,
                    AuthorizationCode = authFlow,
                },
            });

            options.AddSecurityRequirement(
                new OpenApiSecurityRequirement
            {
                {
                    new OpenApiSecurityScheme
                    {
                        Reference = new OpenApiReference
                        {
                            Type = ReferenceType.SecurityScheme,
                            Id   = SecuritySchemeType.OAuth2.ToString(),
                        },
                    },
                    Array.Empty <string>()
                },
            });
        }
        public static OpenApiSecurityScheme LoadSecurityScheme(ParseNode node)
        {
            // Reset the local variables every time this method is called.
            // TODO: Change _flow to a tempStorage variable to make the deserializer thread-safe.
            _flowValue = null;
            _flow      = new OpenApiOAuthFlow();

            var mapNode = node.CheckMapNode("securityScheme");

            var securityScheme = new OpenApiSecurityScheme();

            foreach (var property in mapNode)
            {
                property.ParseField(securityScheme, _securitySchemeFixedFields, _securitySchemePatternFields);
            }

            // Put the Flow object in the right Flows property based on the string in "flow"
            if (_flowValue == OpenApiConstants.Implicit)
            {
                securityScheme.Flows = new OpenApiOAuthFlows
                {
                    Implicit = _flow
                };
            }
            else if (_flowValue == OpenApiConstants.Password)
            {
                securityScheme.Flows = new OpenApiOAuthFlows
                {
                    Password = _flow
                };
            }
            else if (_flowValue == OpenApiConstants.Application)
            {
                securityScheme.Flows = new OpenApiOAuthFlows
                {
                    ClientCredentials = _flow
                };
            }
            else if (_flowValue == OpenApiConstants.AccessCode)
            {
                securityScheme.Flows = new OpenApiOAuthFlows
                {
                    AuthorizationCode = _flow
                };
            }

            return(securityScheme);
        }
예제 #7
0
        public ChangedOAuthFlowBO Diff(OpenApiOAuthFlow left, OpenApiOAuthFlow right)
        {
            var changedOAuthFlow = new ChangedOAuthFlowBO(left, right);

            if (left != null && right != null)
            {
                changedOAuthFlow.ChangedAuthorizationUrl = left.AuthorizationUrl != right.AuthorizationUrl;
                changedOAuthFlow.ChangedTokenUrl         = left.TokenUrl != right.TokenUrl;
                changedOAuthFlow.ChangedRefreshUrl       = left.RefreshUrl != right.RefreshUrl;
            }

            changedOAuthFlow.Extensions = _openApiDiff
                                          .ExtensionsDiff
                                          .Diff(left?.Extensions, right?.Extensions);

            return(ChangedUtils.IsChanged(changedOAuthFlow));
        }
예제 #8
0
        public static IServiceCollection ConfigureSwagger(this IServiceCollection services,
                                                          string azureAdAuthority, string azureAdClientId, string apiName)
        {
            if (apiName == null)
            {
                throw new ArgumentNullException(nameof(apiName));
            }

            services.AddVersionedApiExplorer(options =>
            {
                options.GroupNameFormat = "VVV";
                // Will remove the version tags from the ApiExplorer routes. This will generate cleaner routes in Swagger docs.
                options.SubstituteApiVersionInUrl = true;
            });
            services.AddOpenApiDocument(document =>
            {
                document.Title       = apiName;
                document.Description = "TODO";

                document.Version       = "v1";
                document.DocumentName  = "v1";
                document.ApiGroupNames = new[] { "1" };

                var authFlow = new OpenApiOAuthFlow
                {
                    AuthorizationUrl = $"{azureAdAuthority}/oauth2/authorize?resource={azureAdClientId}",
                    TokenUrl         = $"{azureAdAuthority}/oauth2/token",
                    Scopes           = { { "openid", "openid" } }
                };
                document.AddSecurity("bearer", Enumerable.Empty <string>(),
                                     new OpenApiSecurityScheme
                {
                    Type        = OpenApiSecuritySchemeType.OAuth2,
                    Description = "Azure AD bearer token",
                    Flow        = OpenApiOAuth2Flow.Implicit,
                    In          = OpenApiSecurityApiKeyLocation.Header,
                    Flows       = new OpenApiOAuthFlows()
                    {
                        ClientCredentials = authFlow, Implicit = authFlow
                    }
                });
                document.OperationProcessors.Add(new AspNetCoreOperationSecurityScopeProcessor("bearer"));
            });
            return(services);
        }
예제 #9
0
        private static OpenApiSecurityScheme ConfigureSecurityDefinitionScheme(
            ApiSecurityOptions apiSecurityOptions)
        {
            OpenApiOAuthFlow authCodeFlow = new OpenApiOAuthFlow
            {
                AuthorizationUrl = new Uri($"{apiSecurityOptions.Authority}/connect/authorize"),
                TokenUrl         = new Uri($"{apiSecurityOptions.Authority}/connect/token"),
                Scopes           = new Dictionary <string, string>
                {
                    { apiSecurityOptions.Audience, "Api access" }
                }
            };

            return(new OpenApiSecurityScheme
            {
                Type = SecuritySchemeType.OAuth2,
                Flows = new OpenApiOAuthFlows
                {
                    AuthorizationCode = authCodeFlow
                }
            });
        }
        public void ValidateFixedFieldsIsRequiredInResponse()
        {
            // Arrange
            string authorizationUrlError = String.Format(SRResource.Validation_FieldIsRequired, "authorizationUrl", "OAuth Flow");
            string tokenUrlError         = String.Format(SRResource.Validation_FieldIsRequired, "tokenUrl", "OAuth Flow");
            IEnumerable <OpenApiError> errors;
            OpenApiOAuthFlow           oAuthFlow = new OpenApiOAuthFlow();

            // Act
            var validator = new OpenApiValidator();
            var walker    = new OpenApiWalker(validator);

            walker.Walk(oAuthFlow);

            errors = validator.Errors;
            bool result = !errors.Any();

            // Assert
            Assert.False(result);
            Assert.NotNull(errors);
            Assert.Equal(2, errors.Count());
            Assert.Equal(new[] { authorizationUrlError, tokenUrlError }, errors.Select(e => e.Message));
        }
예제 #11
0
 /// <summary>
 /// Visits <see cref="OpenApiOAuthFlow"/>
 /// </summary>
 public virtual void Visit(OpenApiOAuthFlow openApiOAuthFlow)
 {
 }
예제 #12
0
 /// <summary>
 /// Visits <see cref="OpenApiOAuthFlow"/> and child objects
 /// </summary>
 /// <param name="oAuthFlow"></param>
 internal void Walk(OpenApiOAuthFlow oAuthFlow)
 {
     _visitor.Visit(oAuthFlow);
     Walk(oAuthFlow as IOpenApiExtensible);
 }
예제 #13
0
        private static FlowEntity NewFlowEntity(string name, IList <string> scopeNames, OpenApiOAuthFlow openApiOAuthFlow)
        {
            var scopes = new List <SecurityScopeEntity>();

            foreach (var scopeName in scopeNames)
            {
                var flowScope = openApiOAuthFlow.Scopes.SingleOrDefault(s => s.Key.Equals(scopeName));
                if (flowScope.Value != null)
                {
                    var scope = new SecurityScopeEntity
                    {
                        Name        = scopeName,
                        Description = flowScope.Value
                    };
                    scopes.Add(scope);
                }
            }

            return(new FlowEntity
            {
                Name = name,
                AuthorizationUrl = openApiOAuthFlow.AuthorizationUrl?.ToString(),
                TokenUrl = openApiOAuthFlow.TokenUrl?.ToString(),
                Scopes = scopes
            });
        }
예제 #14
0
        private static OpenApiOAuthFlow ToOAuthFlow(this XElement element, string flowType,
                                                    out IList <string> scopeNames)
        {
            var oAuthFlow = new OpenApiOAuthFlow();

            scopeNames = new List <string>();

            var authorizationUrl = element.Elements()
                                   .FirstOrDefault(p => p.Name == KnownXmlStrings.AuthorizationUrl)?.Value;

            var refreshUrl = element.Elements()
                             .FirstOrDefault(p => p.Name == KnownXmlStrings.RefreshUrl)?.Value;

            var tokenUrl = element.Elements()
                           .FirstOrDefault(p => p.Name == KnownXmlStrings.TokenUrl)?.Value;

            if (flowType == KnownXmlStrings.ImplicitFlow || flowType == KnownXmlStrings.AuthorizationCode)
            {
                if (authorizationUrl == null)
                {
                    throw new InvalidSecurityTagException(string.Format(
                                                              SpecificationGenerationMessages.UndocumentedAuthorizationUrl,
                                                              flowType));
                }
                oAuthFlow.AuthorizationUrl = new Uri(authorizationUrl);
            }

            if (flowType == KnownXmlStrings.Password ||
                flowType == KnownXmlStrings.AuthorizationCode ||
                flowType == KnownXmlStrings.ClientCredentials)
            {
                if (tokenUrl == null)
                {
                    throw new InvalidSecurityTagException(string.Format(
                                                              SpecificationGenerationMessages.UndocumentedTokenUrl,
                                                              flowType));
                }

                oAuthFlow.TokenUrl = new Uri(tokenUrl);
            }

            if (refreshUrl != null)
            {
                oAuthFlow.RefreshUrl = new Uri(refreshUrl);
            }

            var scopeElements = element.Elements()
                                .Where(p => p.Name == KnownXmlStrings.Scope);

            if (!scopeElements.Any())
            {
                throw new InvalidSecurityTagException(string.Format(
                                                          SpecificationGenerationMessages.UndocumentedScopeForFlow,
                                                          flowType));
            }

            foreach (var scopeElement in scopeElements)
            {
                var name = scopeElement.Attribute(KnownXmlStrings.Name)?.Value;

                if (string.IsNullOrWhiteSpace(name))
                {
                    throw new InvalidSecurityTagException(string.Format(
                                                              SpecificationGenerationMessages.UndocumentedName,
                                                              KnownXmlStrings.Scope));
                }

                var description = scopeElement.Elements().FirstOrDefault(p => p.Name == KnownXmlStrings.Description)
                                  ?.Value;

                if (string.IsNullOrWhiteSpace(description))
                {
                    throw new InvalidSecurityTagException(string.Format(
                                                              SpecificationGenerationMessages.UndocumentedDescription,
                                                              KnownXmlStrings.Scope));
                }

                scopeNames.Add(name);
                oAuthFlow.Scopes.Add(name, description);
            }

            return(oAuthFlow);
        }
예제 #15
0
 /// <summary>
 /// Execute validation rules against an <see cref="OpenApiOAuthFlow"/>
 /// </summary>
 /// <param name="item">The object to be validated</param>
 public override void Visit(OpenApiOAuthFlow item) => Validate(item);
예제 #16
0
 public override void Visit(OpenApiOAuthFlow openApiOAuthFlow)
 {
     EncodeCall();
     base.Visit(openApiOAuthFlow);
 }
예제 #17
0
 public ChangedOAuthFlowBO(OpenApiOAuthFlow oldOAuthFlow, OpenApiOAuthFlow newOAuthFlow)
 {
     OldOAuthFlow = oldOAuthFlow;
     NewOAuthFlow = newOAuthFlow;
 }
예제 #18
0
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddApplication();
            services.AddInfrastructure(Configuration);
            services.AddHealthChecks()
            .AddDbContextCheck <ToDoDbContext>();
            services.AddHttpContextAccessor();

            // Customise default API behavour
            services.Configure <ApiBehaviorOptions>(options =>
            {
                options.SuppressModelStateInvalidFilter = true;
            });
            services.AddHttpContextAccessor();
            services.AddScoped <ICurrentUserService, CurrentUserService>();

            services
            .AddControllersWithViews()
            .AddNewtonsoftJson()
            .AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining <IToDoDbContext>());

            services.AddRazorPages();
            string authorizationUrl = "https://appdatadev.b2clogin.com/appdatadev.onmicrosoft.com/B2C_1_signupsignin/oauth2/v2.0/authorize";
            string tokenUrl         =
                "https://appdatadev.b2clogin.com/appdatadev.onmicrosoft.com/B2C_1_signupsignin/oauth2/v2.0/token";
            var scopes = new Dictionary <string, string>
            {
                { "https://appdatadev.onmicrosoft.com/todo/ReadAll", "Read All" },
                { "offline_access", "offline_access" },
                { "email", "email" }
            };
            var swaggerOAuthCodeFlow = new OpenApiOAuthFlow()
            {
                AuthorizationUrl = authorizationUrl,
                TokenUrl         = tokenUrl,
                RefreshUrl       = tokenUrl,
                Scopes           = scopes
            };

            var swaggerOAuthImplicitFlow = new OpenApiOAuthFlow()
            {
                AuthorizationUrl = authorizationUrl,
                RefreshUrl       = tokenUrl,
                // TokenUrl = tokenUrl,
                Scopes = scopes
            };
            var swaggerSecurityCode = new OpenApiSecurityScheme()
            {
                Flows = new OpenApiOAuthFlows()
                {
                    AuthorizationCode = swaggerOAuthCodeFlow,
                    // Implicit = swaggerOAuthFlow
                },


                Type = OpenApiSecuritySchemeType.OAuth2,
            };


            var swaggerSecurityImplicit = new OpenApiSecurityScheme()
            {
                Flows = new OpenApiOAuthFlows()
                {
                    //AuthorizationCode = swaggerOAuthFlow,
                    Implicit = swaggerOAuthImplicitFlow
                },


                Type = OpenApiSecuritySchemeType.OAuth2,
            };

            services.AddSwaggerDocument(o =>
            {
                o.PostProcess = s =>
                {
                    s.Host     = Configuration["SwaggerHost"];
                    s.BasePath = "/";
                    s.Schemes  = new List <OpenApiSchema>()
                    {
                        OpenApiSchema.Https
                    };
                    s.SecurityDefinitions.Add("oauth2code", swaggerSecurityCode);
                    s.SecurityDefinitions.Add("oauth2implicit", swaggerSecurityImplicit);
                    // s.SecurityDefinitions.Add("test",test);
                };
                o.Title       = "ToDo App";
                o.Description = "Yes...Another Todo App";
                o.SchemaType  = SchemaType.Swagger2;
                o.OperationProcessors.Add(new OperationSecurityScopeProcessor("oauth2code"));
                o.OperationProcessors.Add(new OperationSecurityScopeProcessor("oauth2implicit"));
                // o.OperationProcessors.Add(new OperationSecurityScopeProcessor("test"));
                //o.DocumentProcessors.Add(new SecurityDefinitionAppender("oauth2",swaggerSecurity));
            }


                                        );


            //services.AddTransient<IPrincipal>(
            //   provider => provider.GetService<IHttpContextAccessor>().HttpContext?.User);
            // configure strongly typed settings objects
            var appSettingsSection = Configuration.GetSection("AuthenticationOptions");

            services.Configure <AuthenticationOptions>(appSettingsSection);

            // configure jwt authentication
            var authenticationOptions = appSettingsSection.Get <AuthenticationOptions>();

            services.AddAuthentication(o => o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(o =>
            {
                o.Authority = authenticationOptions.Authority;
                o.Audience  = authenticationOptions.Audience;
                o.TokenValidationParameters.ValidateAudience = false;
                o.TokenValidationParameters.ValidateIssuer   = false;
            });



            services.AddAuthorization(o =>
            {
                o.AddPolicy("ReadAll", new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build());
            });

            _services = services;
        }