/// <summary> /// Initializes a new instance of the <see cref="OAuthManager"/> class. /// </summary> /// <param name="log">Log</param> /// <param name="appsManager">apps manager</param> /// <param name="usersManager">users manager</param> /// <param name="identityProvider">OAuth identity provider</param> public OAuthManager(ILog log, IAppsManager appsManager, IUsersManager usersManager, IdentityProviders identityProvider) : base(log, appsManager, usersManager) { this.oauthIdentityProvider = identityProvider; switch (this.oauthIdentityProvider) { case IdentityProviders.Microsoft: this.serverIdentityProvider = IdentityProviderType.Microsoft; break; case IdentityProviders.Facebook: this.serverIdentityProvider = IdentityProviderType.Facebook; break; case IdentityProviders.Google: this.serverIdentityProvider = IdentityProviderType.Google; break; case IdentityProviders.Twitter: this.serverIdentityProvider = IdentityProviderType.Twitter; break; default: throw new InvalidOperationException("Code should never reach here."); } }
private static void FetchMetadata(Logging.IInternalLogger logger, IdentityProviders identityProviders, string metadataLocation) { // Get new metadata files foreach (var identityProvider in identityProviders) { logger.DebugFormat("Attempting to fetch SAML metadata file for identity provider {0}", identityProvider.Id); var metadataEndpoint = identityProvider.Endpoints.FirstOrDefault(x => x.Type == EndpointType.Metadata); if (metadataEndpoint == null) { continue; } var metadataEndpointUrl = metadataEndpoint.Url; var metadataFile = Path.Combine(metadataLocation, identityProvider.Id + ".xml"); // Fetch new file try { var client = new WebClient(); client.DownloadFile(metadataEndpointUrl, metadataFile + ".new"); // Wipe old file if (File.Exists(metadataFile)) { File.Delete(metadataFile); } // Move new file into place File.Move(metadataFile + ".new", metadataFile); logger.DebugFormat("Successfully updated SAML metadata file for identity provider {0}", identityProvider.Id); } catch (WebException ex) { logger.Warn(string.Format("Unable to fetch SAML metadata file for identity provider {0}", identityProvider.Id), ex); } } }
/// <summary> /// Implements the <c>OAuth</c> Implicit Flow. In this flow, a user authorizes the IdentityProvider to issue an access token. The client receives the /// access token and uses it to fetch the user profile. For this, it calls the appropriate fetch profile API offered by the identity provider. /// The implicit flow is considered an insecure form of authentication because an identity provider allows anyone to retrieve a profile /// with the access token. /// </summary> /// <param name="idProvider">third party identity provider</param> /// <param name="userAccessToken">user access token</param> /// <returns>the user profile</returns> public async Task <UserProfile> ImplicitFlow(IdentityProviders idProvider, string userAccessToken) { switch (idProvider) { case IdentityProviders.Microsoft: return(new UserProfile { IdProvider = IdentityProviders.Microsoft, MicrosoftProfile = await this.MicrosoftImplicitFlow(userAccessToken), }); case IdentityProviders.Facebook: return(new UserProfile { IdProvider = IdentityProviders.Facebook, FacebookProfile = await this.FacebookImplicitFlow(userAccessToken), }); case IdentityProviders.Google: return(new UserProfile { IdProvider = IdentityProviders.Google, GoogleProfile = await this.GoogleImplicitFlow(userAccessToken), }); } throw new OAuthException(OAuthErrors.NotImplemented_501); }
private Saml2Configuration GetSamlConfiguration() { var myconfig = new Saml2Configuration { ServiceProvider = new ServiceProvider { SigningCertificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(FileEmbeddedResource("SelfHostOwinSPExample.sts_dev_certificate.pfx"), "test1234", System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.MachineKeySet), Server = "https://localhost:44333/core", Id = "https://localhost:44333/core" }, AllowedAudienceUris = new System.Collections.Generic.List <Uri>(new[] { new Uri("https://localhost:44333/core") }) }; myconfig.ServiceProvider.Endpoints.AddRange(new[] { new ServiceProviderEndpoint(EndpointType.SignOn, "/core/saml2/login", "/core"), new ServiceProviderEndpoint(EndpointType.Logout, "/core/saml2/logout", "/core"), new ServiceProviderEndpoint(EndpointType.Metadata, "/core/saml2/metadata") }); var idpSource = new IdentityProviders(); idpSource.AddByMetadataDirectory("..\\..\\Metadata"); //myconfig.IdentityProviders.AddByMetadataUrl(new Uri("https://tas.fhict.nl/identity/saml2/metadata")); idpSource.First().OmitAssertionSignatureCheck = true; myconfig.IdentityProvidersSource = idpSource; myconfig.LoggingFactoryType = "SAML2.Logging.DebugLoggerFactory"; return(myconfig); }
/// <summary> /// Gets friends from a third-party identity provider. The definition of a "friend" depends on the third-party provider., /// "Friends" are friends (for Facebook), following users (for Twitter), and contacts (for Google and Microsoft). /// The access token must have the appropriate scopes to retrieve the list of friends. /// </summary> /// <param name="idProvider">third party identity provider</param> /// <param name="userAccessToken">user access token</param> /// <returns>the user profile</returns> public async Task <List <UserProfile> > GetFriends(IdentityProviders idProvider, string userAccessToken) { // data field is a list of Facebook profiles. Convert them to our own user profiles List <UserProfile> userProfileList = new List <UserProfile>(); // We only support Facebook for now switch (idProvider) { case IdentityProviders.Facebook: List <FacebookProfile> fbProfiles = await this.GetFacebookFriendsImplicitFlow(userAccessToken); foreach (var p in fbProfiles) { var userProfile = new UserProfile { IdProvider = idProvider, FacebookProfile = p }; userProfileList.Add(userProfile); } return(userProfileList); } throw new OAuthException(OAuthErrors.NotImplemented_501); }
/// <summary> /// Implements the <c>OAuth</c> Authorization Code Flow. In this flow, a user authorizes the IdentityProvider to issue a code. The client receives the code /// and can exchange it for an access token. The access token is used to fetch the user profile. /// This flow is more secure the Implicit flow. This is because only the client can exchange the code for the access token. This is done by the library /// when called by the client (this should be done only by clients running as servers or in the cloud). It should not be done by clients running /// on user's mobile devices or browsers. /// </summary> /// <param name="idProvider">third party identity provider</param> /// <param name="userCode">user code</param> /// <param name="clientId">client application ID</param> /// <param name="clientSecret">client application secret</param> /// <param name="clientRedirectURI">client redirection URI; must not be null in case of Google</param> /// <param name="userRequestToken">request token; must not be null in case of Twitter</param> /// <returns>the user profile</returns> public async Task <UserProfile> AuthorizationCodeFlow(IdentityProviders idProvider, string userCode, string clientId, string clientSecret, string clientRedirectURI = null, string userRequestToken = null) { switch (idProvider) { case IdentityProviders.Google: if (string.IsNullOrEmpty(clientRedirectURI)) { // clientRedirectURI must be present throw new OAuthException(OAuthErrors.BadRequest_400); } return(new UserProfile { IdProvider = IdentityProviders.Google, GoogleProfile = await this.GoogleAuthorizationCodeFlow(userCode, clientId, clientSecret, clientRedirectURI), }); case IdentityProviders.Twitter: if (string.IsNullOrEmpty(userRequestToken)) { // userRequestToken must be present throw new OAuthException(OAuthErrors.BadRequest_400); } return(new UserProfile { IdProvider = IdentityProviders.Twitter, TwitterProfile = await this.TwitterAuthorizationCodeFlow(userRequestToken, userCode, clientId, clientSecret), }); } throw new OAuthException(OAuthErrors.NotImplemented_501); }
internal AuthConfigData(ResourceIdentifier id, string name, ResourceType resourceType, SystemData systemData, AuthPlatform platform, GlobalValidation globalValidation, IdentityProviders identityProviders, ContainerAppLogin login, HttpSettings httpSettings) : base(id, name, resourceType, systemData) { Platform = platform; GlobalValidation = globalValidation; IdentityProviders = identityProviders; Login = login; HttpSettings = httpSettings; }
private IdentityProviders ToIdentityProviders(IEnumerable<IdentityProvider> providers, IdentityProviderCollection config) { var idps = new IdentityProviders(providers) { Encodings = config.Encodings, SelectionUrl = config.SelectionUrl }; idps.AddByMetadataDirectory(config.MetadataLocation); return idps; }
private IdentityProviders ToIdentityProviders(IEnumerable <IdentityProvider> providers, IdentityProviderCollection config) { var idps = new IdentityProviders(providers) { Encodings = config.Encodings, SelectionUrl = config.SelectionUrl }; idps.AddByMetadataDirectory(config.MetadataLocation); return(idps); }
/// <summary> /// Obtains third party request tokens. This code needs more revising. /// </summary> /// <param name="idProvider">external identity provider</param> /// <param name="clientId">the id of the application on behalf of which the request token is requested</param> /// <param name="clientSecret">the secret of the application on behalf of which the request token is requested</param> /// <param name="clientRedirectURI">the <c>oauth</c> callback of the application on behalf of which the request token is requested</param> /// <returns>request token</returns> public async Task <string> GetRequestToken(IdentityProviders idProvider, string clientId, string clientSecret, string clientRedirectURI) { // Implements simple dispatcher to private functions depending on the third party provider switch (idProvider) { case IdentityProviders.Twitter: { return(await this.GetTwitterRequestToken(clientId, clientSecret, clientRedirectURI)); } } throw new OAuthException(OAuthErrors.NotImplemented_501); }
//[ExpectedException(typeof(Saml20Exception), ExpectedMessage = "Assertion is no longer valid.")] public void CanDecryptFOBSAssertion() { // Arrange var doc = AssertionUtil.LoadBase64EncodedXmlDocument(@"Assertions\fobs-assertion2"); var encryptedList = doc.GetElementsByTagName(EncryptedAssertion.ElementName, Saml20Constants.Assertion); // Do some mock configuration. var idpSource = new IdentityProviders(); var config = new Saml2Configuration { AllowedAudienceUris = new System.Collections.Generic.List <Uri>(), IdentityProvidersSource = idpSource }; config.AllowedAudienceUris.Add(new Uri("https://saml.safewhere.net")); idpSource.AddByMetadataDirectory(@"Protocol\MetadataDocs\FOBS"); // Set it manually. var cert = new X509Certificate2(@"Certificates\SafewhereTest_SFS.pfx", "test1234"); var encryptedAssertion = new Saml20EncryptedAssertion((RSA)cert.PrivateKey); encryptedAssertion.LoadXml((XmlElement)encryptedList[0]); // Act encryptedAssertion.Decrypt(); // Retrieve metadata var assertion = new Saml20Assertion(encryptedAssertion.Assertion.DocumentElement, null, false, TestConfiguration.Configuration); var endp = config.IdentityProvidersSource.GetById(assertion.Issuer); // Assert Assert.That(encryptedList.Count == 1); Assert.IsNotNull(endp, "Endpoint not found"); Assert.IsNotNull(endp.Metadata, "Metadata not found"); try { assertion.CheckValid(AssertionUtil.GetTrustedSigners(assertion.Issuer)); Assert.Fail("Verification should fail. Token does not include its signing key."); } catch (InvalidOperationException) { } Assert.IsNull(assertion.SigningKey, "Signing key is already present on assertion. Modify test."); //Assert.IsTrue("We have tested this next test" == ""); //Assert.That(assertion.CheckSignature(Saml20SignonHandler.GetTrustedSigners(endp.Metadata.GetKeys(KeyTypes.Signing), endp))); //Assert.IsNotNull(assertion.SigningKey, "Signing key was not set on assertion instance."); }
public IEnumerable <ValidationResult> Validate(ValidationContext validationContext) { foreach (var application in Applications) { var name = application.IdentityProviderBinding.Name; if (!IdentityProviders.Any(i => i.Name == name)) { yield return(new ValidationResult($"No identity provider with name '{name}' configured.", new string[] { nameof(Applications) })); } if (application.AuthenticatorBindings != null) { foreach (var authBinding in application.AuthenticatorBindings) { var authName = authBinding.Name; if (Authenticators is null || !Authenticators.Any(a => a.Name == authName)) { yield return(new ValidationResult($"No authenticator with name '{authName}' configured.", new string[] { nameof(Applications) })); } } } } }
public Saml2Configuration TestEnvironmentConfiguration() { var myconfig = new Saml2Configuration { ServiceProvider = new ServiceProvider { SigningCertificate = new System.Security.Cryptography.X509Certificates.X509Certificate2("../../Metadata-Test/certificate.pfx", "", System.Security.Cryptography.X509Certificates.X509KeyStorageFlags.MachineKeySet), Server = "http://localhost:7777/identity", Id = "http://localhost:7777/identity" } }; myconfig.ServiceProvider.Endpoints.AddRange(new[] { new ServiceProviderEndpoint(EndpointType.SignOn, "/identity/login", "/identity", BindingType.Redirect), new ServiceProviderEndpoint(EndpointType.Logout, "/identity/logout", "/identity", BindingType.Redirect), new ServiceProviderEndpoint(EndpointType.Metadata, "/identity/metadata") }); var idpSource = new IdentityProviders(); idpSource.AddByMetadata("..\\..\\Metadata-Test\\uat.xml"); myconfig.IdentityProvidersSource = idpSource; SAML2.Logging.LoggerProvider.Configuration = myconfig; return(myconfig); }
// This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddAutoMapper(typeof(Startup)); services.AddRazorPages(); services.AddDbContext <PostgresDbContext>( options => options.UseNpgsql( this.Configuration.GetConnectionString("PostgreSQL") ), ServiceLifetime.Transient); var identityConfig = new IdentityProviders(); this.Configuration.GetSection(nameof(IdentityProviders)).Bind(identityConfig); services.AddAuthentication(o => { o.DefaultScheme = IdentityConstants.ApplicationScheme; o.DefaultSignInScheme = IdentityConstants.ExternalScheme; }) .AddIdentityProviders(identityConfig) .AddIdentityCookies(); services.AddIdentityCore <ApplicationUser>(o => { o.Stores.MaxLengthForKeys = 128; o.SignIn.RequireConfirmedAccount = false; }) .AddDefaultUI() .AddDefaultTokenProviders() .AddRoles <IdentityRole>() .AddRoleManager <RoleManager <IdentityRole> >() .AddEntityFrameworkStores <PostgresDbContext>(); services.AddServerSideBlazor() // TODO change to client-side .AddCircuitOptions(options => { if (this.env.IsDevelopment()) { options.DetailedErrors = true; } }); services.AddWebOptimizer(pipeline => { pipeline.AddBundle( "/css/style.css", "text/css; charset=UTF-8", "/wwwroot/scss/style.scss") .UseContentRoot() .CompileScss() .Concatenate() .FingerprintUrls() .AddResponseHeader("X-Content-Type-Options", "nosniff") .MinifyCss(); }); services.AddTransient <BlazorHelper>(); services.AddTransient <BlogPostService>(); services.AddTransient <CategoryService>(); // TODO Move to Api project services.AddTransient <CategoryController>(); services.AddTransient <BlogPostController>(); services.AddTransient <IRepository <BlogPostEntity>, Repository <BlogPostEntity> >(); services.AddTransient <ICategoryRepository, CategoryRepository>(); services.AddScoped <HeadState>(); }
internal static AuthConfigData DeserializeAuthConfigData(JsonElement element) { ResourceIdentifier id = default; string name = default; ResourceType type = default; SystemData systemData = default; Optional <AuthPlatform> platform = default; Optional <GlobalValidation> globalValidation = default; Optional <IdentityProviders> identityProviders = default; Optional <ContainerAppLogin> login = default; Optional <HttpSettings> httpSettings = default; foreach (var property in element.EnumerateObject()) { if (property.NameEquals("id")) { id = new ResourceIdentifier(property.Value.GetString()); continue; } if (property.NameEquals("name")) { name = property.Value.GetString(); continue; } if (property.NameEquals("type")) { type = property.Value.GetString(); continue; } if (property.NameEquals("systemData")) { systemData = JsonSerializer.Deserialize <SystemData>(property.Value.ToString()); continue; } if (property.NameEquals("properties")) { if (property.Value.ValueKind == JsonValueKind.Null) { property.ThrowNonNullablePropertyIsNull(); continue; } foreach (var property0 in property.Value.EnumerateObject()) { if (property0.NameEquals("platform")) { if (property0.Value.ValueKind == JsonValueKind.Null) { property0.ThrowNonNullablePropertyIsNull(); continue; } platform = AuthPlatform.DeserializeAuthPlatform(property0.Value); continue; } if (property0.NameEquals("globalValidation")) { if (property0.Value.ValueKind == JsonValueKind.Null) { property0.ThrowNonNullablePropertyIsNull(); continue; } globalValidation = GlobalValidation.DeserializeGlobalValidation(property0.Value); continue; } if (property0.NameEquals("identityProviders")) { if (property0.Value.ValueKind == JsonValueKind.Null) { property0.ThrowNonNullablePropertyIsNull(); continue; } identityProviders = IdentityProviders.DeserializeIdentityProviders(property0.Value); continue; } if (property0.NameEquals("login")) { if (property0.Value.ValueKind == JsonValueKind.Null) { property0.ThrowNonNullablePropertyIsNull(); continue; } login = ContainerAppLogin.DeserializeContainerAppLogin(property0.Value); continue; } if (property0.NameEquals("httpSettings")) { if (property0.Value.ValueKind == JsonValueKind.Null) { property0.ThrowNonNullablePropertyIsNull(); continue; } httpSettings = HttpSettings.DeserializeHttpSettings(property0.Value); continue; } } continue; } } return(new AuthConfigData(id, name, type, systemData, platform.Value, globalValidation.Value, identityProviders.Value, login.Value, httpSettings.Value)); }
public static AuthenticationBuilder AddIdentityProviders(this AuthenticationBuilder authenticationBuilder, IdentityProviders config) { if (config.Facebook != null) { authenticationBuilder.AddFacebook(options => { options.AppId = config.Facebook.AppId; options.AppSecret = config.Facebook.AppSecret; }); } if (config.Google != null) { authenticationBuilder.AddGoogle(options => { options.ClientId = config.Google.ClientId; options.ClientSecret = config.Google.ClientSecret; }); } if (config.Twitter != null) { authenticationBuilder.AddTwitter(options => { options.ConsumerKey = config.Twitter.ApiKey; options.ConsumerSecret = config.Twitter.ApiSecret; }); } return(authenticationBuilder); }
public Saml2Configuration() { IdentityProviders = new IdentityProviders(); AllowedAudienceUris = new List<System.Uri>(); Metadata = new Metadata(); }
/// <summary> /// Invokes the IDP selection event handler. /// </summary> /// <param name="endpoints">The endpoints.</param> /// <returns>The <see cref="IdentityProvider"/>.</returns> public static IdentityProvider InvokeIDPSelectionEventHandler(IdentityProviders endpoints) { return(IdpSelectionEvent != null?IdpSelectionEvent(endpoints) : null); }
/// <summary> /// Invokes the IDP selection event handler. /// </summary> /// <param name="endpoints">The endpoints.</param> /// <returns>The <see cref="IdentityProvider"/>.</returns> public static IdentityProvider InvokeIDPSelectionEventHandler(IdentityProviders endpoints) { return IdpSelectionEvent != null ? IdpSelectionEvent(endpoints) : null; }