Ejemplo n.º 1
0
        private static void ConfigureIdentityCreationAndCustomHandlers(IAppBuilder app, OpenIdConnectAuthenticationOptions identityOptions, bool autoLinkExternalAccount = false)
        {
            // Configure AutoLinking, which allows Umbraco to automatically add a first-time
            // visitor to its database without prompting the user.
            identityOptions.SetExternalSignInAutoLinkOptions
            (
                new ExternalSignInAutoLinkOptions(autoLinkExternalAccount: autoLinkExternalAccount,
                                                  defaultUserGroups: null,
                                                  defaultCulture: null)
            );

            // Here we customize two event handlers, one for transforming the claims recevied and another for
            // making sure the IdP Url is set (as the authority uri) in the OpenIdConnect request so it becomes
            // easily accessible to the rest of the processing pipeline. The ReadySignOn mobile app uses the
            // IdP Url to search for maching record(s) in its secure vault upong receving an authentication request.

            identityOptions.Notifications
                = new OpenIdConnectAuthenticationNotifications
                {
                SecurityTokenValidated = ClaimsTransformer.GenerateUserIdentityAsync,           // See code of ClaimsTransformer class for details.

                RedirectToIdentityProvider = n =>
                {
                    n.ProtocolMessage.IdentityProvider = identityOptions.Authority;           // The IdP will decide its own best url if this is not set here.
                    return(Task.FromResult(0));
                }
                };

            app.UseOpenIdConnectAuthentication(identityOptions);    // Don't forget this line and updating the web.config with <add key="owin:appStartup" value="UmbracoCustomOwinStartup" />
        }
        public void Configuration(IAppBuilder app)
        {
            //Configure the Identity user manager for use with Umbraco Back office

            // *** EXPERT: There are several overloads of this method that allow you to specify a custom UserStore or even a custom UserManager!
            app.ConfigureUserManagerForUmbracoBackOffice(
                ApplicationContext.Current,
                //The Umbraco membership provider needs to be specified in order to maintain backwards compatibility with the
                // user password formats. The membership provider is not used for authentication, if you require custom logic
                // to validate the username/password against an external data source you can create create a custom UserManager
                // and override CheckPasswordAsync
                global::Umbraco.Core.Security.MembershipProviderExtensions.GetUsersMembershipProvider().AsUmbracoMembershipProvider());

            //Ensure owin is configured for Umbraco back office authentication
            app
            .UseUmbracoBackOfficeCookieAuthentication(ApplicationContext.Current)
            .UseUmbracoBackOfficeExternalCookieAuthentication(ApplicationContext.Current);

            var identityOptions = new OpenIdConnectAuthenticationOptions
            {
                ClientId = "u-client-bo",
                SignInAsAuthenticationType = Constants.Security.BackOfficeExternalAuthenticationType,
                Authority             = "http://localhost:5000",
                RedirectUri           = "http://localhost:5003/umbraco",
                PostLogoutRedirectUri = "http://localhost:5003/umbraco",
                ResponseType          = "code id_token token",
                Scope = "openid profile email application.profile application.policy"
            };

            // Configure BackOffice Account Link button and style
            identityOptions.ForUmbracoBackOffice("btn-microsoft", "fa-windows");
            identityOptions.Caption = "OpenId Connect";

            // Fix Authentication Type
            identityOptions.AuthenticationType = "http://localhost:5000";

            // Configure AutoLinking
            identityOptions.SetExternalSignInAutoLinkOptions(new ExternalSignInAutoLinkOptions(
                                                                 autoLinkExternalAccount: true,
                                                                 defaultUserGroups: null,
                                                                 defaultCulture: null
                                                                 ));

            identityOptions.Notifications = new OpenIdConnectAuthenticationNotifications
            {
                SecurityTokenValidated = EnrollUser.GenerateIdentityAsync
            };

            app.UseOpenIdConnectAuthentication(identityOptions);
        }
Ejemplo n.º 3
0
    public static void ConfigureBackOfficeAzureActiveDirectoryA2BAuth(this IAppBuilder app,
                                                                      string tenant,
                                                                      string clientId,
                                                                      string clientSecret,
                                                                      string redirectUri,
                                                                      string signUpPolicyId,
                                                                      string signInPolicyId,
                                                                      string userProfilePolicyId,

                                                                      string adminClientId,
                                                                      string adminClientSecret,

                                                                      //Guid issuerId,
                                                                      string caption = "Active Directory", string style = "btn-microsoft", string icon = "fa-windows")
    {
        //ORIGINAL OPTIONS SUPPLIED BY SAMPLE B2C APP

        //var options = new OpenIdConnectAuthenticationOptions
        //{
        //    // These are standard OpenID Connect parameters, with values pulled from web.config
        //    ClientId = clientId,
        //    RedirectUri = redirectUri,
        //    PostLogoutRedirectUri = redirectUri,
        //    Notifications = new OpenIdConnectAuthenticationNotifications
        //    {
        //        AuthenticationFailed = AuthenticationFailed,
        //        RedirectToIdentityProvider = OnRedirectToIdentityProvider,
        //    },
        //    Scope = "openid",
        //    ResponseType = "id_token",

        //    // The PolicyConfigurationManager takes care of getting the correct Azure AD authentication
        //    // endpoints from the OpenID Connect metadata endpoint.  It is included in the PolicyAuthHelpers folder.
        //    ConfigurationManager = new PolicyConfigurationManager(
        //        string.Format(CultureInfo.InvariantCulture, AADInstance, tenant, "/v2.0", OIDCMetadataSuffix),
        //        new string[] { signUpPolicyId, signInPolicyId, userProfilePolicyId }),

        //    // This piece is optional - it is used for displaying the user's name in the navigation bar.
        //    TokenValidationParameters = new TokenValidationParameters
        //    {
        //        NameClaimType = "name"
        //    },
        //};

        var adOptions = new OpenIdConnectAuthenticationOptions
        {
            ClientId              = clientId,
            RedirectUri           = redirectUri,
            PostLogoutRedirectUri = redirectUri,
            Notifications         = new OpenIdConnectAuthenticationNotifications
            {
                //AuthenticationFailed = AuthenticationFailed,
                RedirectToIdentityProvider = OnRedirectToIdentityProvider,

                ////When the user is authorized and we are not asking for an id_token (see way below for details on that),
                //// we will get an auth code which we can then use to retrieve information about the user.
                //AuthorizationCodeReceived = async notification =>
                //{
                //    // The user's objectId is extracted from the claims provided in the id_token, and used to cache tokens in ADAL
                //    // The authority is constructed by appending your B2C directory's name to "https://login.microsoftonline.com/"
                //    // The client credential is where you provide your application secret, and is used to authenticate the application to Azure AD
                //    var userObjectId = notification.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
                //    var authority = string.Format(CultureInfo.InvariantCulture, AADInstance, tenant, string.Empty, string.Empty);
                //    var credential = new ClientCredential(clientId, clientSecret);

                //    // We don't care which policy is used to access the TaskService, so let's use the most recent policy as indicated in the sign-in token
                //    var mostRecentPolicy = notification.AuthenticationTicket.Identity.FindFirst(AcrClaimType).Value;

                //    // The Authentication Context is ADAL's primary class, which represents your connection to your B2C directory
                //    // ADAL uses an in-memory token cache by default.  In this case, we've extended the default cache to use a simple per-user session cache
                //    var authContext = new AuthenticationContext(authority, new NaiveSessionCache(userObjectId));

                //    // Here you ask for a token using the web app's clientId as the scope, since the web app and service share the same clientId.
                //    // The token will be stored in the ADAL token cache, for use in our controllers
                //    var result = await authContext.AcquireTokenByAuthorizationCodeAsync(notification.Code, new Uri(redirectUri), credential, new string[] { clientId }, mostRecentPolicy);

                //    //var userDetails = await GetUserByObjectId(result, userObjectId, tenant, clientId, clientSecret);

                //    var asdf = result;
                //},
                MessageReceived = notification =>
                {
                    return(Task.FromResult(0));
                },
                SecurityTokenReceived = notification =>
                {
                    return(Task.FromResult(0));
                },
                SecurityTokenValidated = notification =>
                {
                    //var userObjectId = notification.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
                    //var authority = string.Format(CultureInfo.InvariantCulture, AADInstance, tenant, string.Empty, string.Empty);
                    //var credential = new ClientCredential(clientId, clientSecret);

                    // We don't care which policy is used to access the TaskService, so let's use the most recent policy
                    //var mostRecentPolicy = notification.AuthenticationTicket.Identity.FindFirst(AcrClaimType).Value;

                    // Here you ask for a token using the web app's clientId as the scope, since the web app and service share the same clientId.
                    // AcquireTokenSilentAsync will return a token from the token cache, and throw an exception if it cannot do so.
                    //var authContext = new AuthenticationContext(authority, new NaiveSessionCache(userObjectId));

                    //var result = await authContext.AcquireTokenSilentAsync(new string[] { clientId }, credential, UserIdentifier.AnyUser, mostRecentPolicy);

                    // Here you ask for a token using the web app's clientId as the scope, since the web app and service share the same clientId.
                    // The token will be stored in the ADAL token cache, for use in our controllers
                    //var result = await authContext.AcquireTokenByAuthorizationCodeAsync(notification.Code, new Uri(redirectUri), credential, new string[] { clientId }, mostRecentPolicy);

                    //var asdf = result;



                    //The returned identity doesn't actually have 'email' as a claim, but instead has a collection of "emails", so we're going to ensure one is
                    // in there and then set the Email claim to be the first so that auto-signin works
                    var emails = notification.AuthenticationTicket.Identity.FindFirst("emails");
                    if (emails != null)
                    {
                        var email = emails.Value;
                        notification.AuthenticationTicket.Identity.AddClaim(new Claim(ClaimTypes.Email, email));
                    }


                    return(Task.FromResult(0));
                }
            },

            //NOTE: in this article they are requesting this scope: https://azure.microsoft.com/en-us/documentation/articles/active-directory-b2c-devquickstarts-web-api-dotnet/
            // I'm unsure if we leave off the offline_access part if we'd get an authcode request back or not, so leaving it here
            // for now since it is working.
            //Scope = "openid offline_access",

            Scope = "openid",

            //NOTE: If we ask for this, then we'll simply get an ID Token back which we cannot use to request
            // additional data of the user. We need to get an authorization code reponse (I'm not sure what the
            // string value for that is but if we don't specify then it's the default).
            ResponseType = "id_token",

            // The PolicyConfigurationManager takes care of getting the correct Azure AD authentication
            // endpoints from the OpenID Connect metadata endpoint.  It is included in the PolicyAuthHelpers folder.
            // The first parameter is the metadata URL of your B2C directory
            // The second parameter is an array of the policies that your app will use.
            ConfigurationManager = new PolicyConfigurationManager(
                string.Format(CultureInfo.InvariantCulture, AADInstance, tenant, "/v2.0", OIDCMetadataSuffix),
                new string[] { signUpPolicyId, signInPolicyId, userProfilePolicyId }),

            // This piece is optional - it is used for displaying the user's name in the navigation bar.
            TokenValidationParameters = new TokenValidationParameters
            {
                NameClaimType = "name",
            },

            SignInAsAuthenticationType = Umbraco.Core.Constants.Security.BackOfficeExternalAuthenticationType
        };

        adOptions.SetChallengeResultCallback(context => new AuthenticationProperties(
                                                 new Dictionary <string, string>
        {
            { UmbracoADAuthExtensions.PolicyKey, signInPolicyId }
        })
        {
            RedirectUri = "/Umbraco",
        });

        var orig = adOptions.AuthenticationType;

        adOptions.ForUmbracoBackOffice(style, icon);
        adOptions.AuthenticationType = orig;

        adOptions.Caption = caption;

        //NOTE: This needs to be set after the ForUmbracoBackOffice
        // this needs to be set to what AD returns otherwise you cannot unlink an account
        adOptions.AuthenticationType = string.Format(
            CultureInfo.InvariantCulture,
            "https://login.microsoftonline.com/{0}/v2.0/",
            //Not sure where this comes from! ... perhaps 'issuerId', but i don't know where to find this,
            // i just know this based on the response we get from B2C
            "ae25bf5e-871e-454a-a1b6-a3560a09ec5e");

        //This will auto-create users based on the authenticated user if they are new
        //NOTE: This needs to be set after the explicit auth type is set
        adOptions.SetExternalSignInAutoLinkOptions(new ExternalSignInAutoLinkOptions(autoLinkExternalAccount: true));

        app.UseOpenIdConnectAuthentication(adOptions);
    }
Ejemplo n.º 4
0
	public static void ConfigureBackOfficeAzureActiveDirectoryA2BAuth(this IAppBuilder app, 
		string tenant, 
		string clientId, 
		string clientSecret, 
		string redirectUri, 
		string signUpPolicyId, 
		string signInPolicyId, 
		string userProfilePolicyId,
		
		string adminClientId,
		string adminClientSecret,
		
		//Guid issuerId,
		string caption = "Active Directory", string style = "btn-microsoft", string icon = "fa-windows")
	{

		//ORIGINAL OPTIONS SUPPLIED BY SAMPLE B2C APP

		//var options = new OpenIdConnectAuthenticationOptions
		//{
		//    // These are standard OpenID Connect parameters, with values pulled from web.config
		//    ClientId = clientId,
		//    RedirectUri = redirectUri,
		//    PostLogoutRedirectUri = redirectUri,
		//    Notifications = new OpenIdConnectAuthenticationNotifications
		//    {
		//        AuthenticationFailed = AuthenticationFailed,
		//        RedirectToIdentityProvider = OnRedirectToIdentityProvider,
		//    },
		//    Scope = "openid",
		//    ResponseType = "id_token",

		//    // The PolicyConfigurationManager takes care of getting the correct Azure AD authentication
		//    // endpoints from the OpenID Connect metadata endpoint.  It is included in the PolicyAuthHelpers folder.
		//    ConfigurationManager = new PolicyConfigurationManager(
		//        string.Format(CultureInfo.InvariantCulture, AADInstance, tenant, "/v2.0", OIDCMetadataSuffix),
		//        new string[] { signUpPolicyId, signInPolicyId, userProfilePolicyId }),

		//    // This piece is optional - it is used for displaying the user's name in the navigation bar.
		//    TokenValidationParameters = new TokenValidationParameters
		//    {
		//        NameClaimType = "name"
		//    },
		//};

		var adOptions = new OpenIdConnectAuthenticationOptions
		{                         
			ClientId = clientId,                
			RedirectUri = redirectUri,
			PostLogoutRedirectUri = redirectUri,
			Notifications = new OpenIdConnectAuthenticationNotifications
			{
				//AuthenticationFailed = AuthenticationFailed,
				RedirectToIdentityProvider = OnRedirectToIdentityProvider,

				////When the user is authorized and we are not asking for an id_token (see way below for details on that),
				//// we will get an auth code which we can then use to retrieve information about the user.
				//AuthorizationCodeReceived = async notification =>
				//{
				//    // The user's objectId is extracted from the claims provided in the id_token, and used to cache tokens in ADAL
				//    // The authority is constructed by appending your B2C directory's name to "https://login.microsoftonline.com/"
				//    // The client credential is where you provide your application secret, and is used to authenticate the application to Azure AD
				//    var userObjectId = notification.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
				//    var authority = string.Format(CultureInfo.InvariantCulture, AADInstance, tenant, string.Empty, string.Empty);
				//    var credential = new ClientCredential(clientId, clientSecret);

				//    // We don't care which policy is used to access the TaskService, so let's use the most recent policy as indicated in the sign-in token
				//    var mostRecentPolicy = notification.AuthenticationTicket.Identity.FindFirst(AcrClaimType).Value;

				//    // The Authentication Context is ADAL's primary class, which represents your connection to your B2C directory
				//    // ADAL uses an in-memory token cache by default.  In this case, we've extended the default cache to use a simple per-user session cache
				//    var authContext = new AuthenticationContext(authority, new NaiveSessionCache(userObjectId));

				//    // Here you ask for a token using the web app's clientId as the scope, since the web app and service share the same clientId.
				//    // The token will be stored in the ADAL token cache, for use in our controllers
				//    var result = await authContext.AcquireTokenByAuthorizationCodeAsync(notification.Code, new Uri(redirectUri), credential, new string[] { clientId }, mostRecentPolicy);

				//    //var userDetails = await GetUserByObjectId(result, userObjectId, tenant, clientId, clientSecret);

				//    var asdf = result;
				//},
				MessageReceived = notification =>
				{
					return Task.FromResult(0);
				},
				SecurityTokenReceived = notification =>
				{
					return Task.FromResult(0);
				},
				SecurityTokenValidated = notification =>
				{
					//var userObjectId = notification.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
					//var authority = string.Format(CultureInfo.InvariantCulture, AADInstance, tenant, string.Empty, string.Empty);
					//var credential = new ClientCredential(clientId, clientSecret);

					// We don't care which policy is used to access the TaskService, so let's use the most recent policy
					//var mostRecentPolicy = notification.AuthenticationTicket.Identity.FindFirst(AcrClaimType).Value;

					// Here you ask for a token using the web app's clientId as the scope, since the web app and service share the same clientId.
					// AcquireTokenSilentAsync will return a token from the token cache, and throw an exception if it cannot do so.
					//var authContext = new AuthenticationContext(authority, new NaiveSessionCache(userObjectId));

					//var result = await authContext.AcquireTokenSilentAsync(new string[] { clientId }, credential, UserIdentifier.AnyUser, mostRecentPolicy);

					// Here you ask for a token using the web app's clientId as the scope, since the web app and service share the same clientId.
					// The token will be stored in the ADAL token cache, for use in our controllers
					//var result = await authContext.AcquireTokenByAuthorizationCodeAsync(notification.Code, new Uri(redirectUri), credential, new string[] { clientId }, mostRecentPolicy);

					//var asdf = result;



					//The returned identity doesn't actually have 'email' as a claim, but instead has a collection of "emails", so we're going to ensure one is 
					// in there and then set the Email claim to be the first so that auto-signin works
					var emails = notification.AuthenticationTicket.Identity.FindFirst("emails");
					if (emails != null)
					{
						var email = emails.Value;
						notification.AuthenticationTicket.Identity.AddClaim(new Claim(ClaimTypes.Email, email));
					}
					

					return Task.FromResult(0);
				}                    
			},

			//NOTE: in this article they are requesting this scope: https://azure.microsoft.com/en-us/documentation/articles/active-directory-b2c-devquickstarts-web-api-dotnet/
			// I'm unsure if we leave off the offline_access part if we'd get an authcode request back or not, so leaving it here
			// for now since it is working.
			//Scope = "openid offline_access",

			Scope = "openid",

			//NOTE: If we ask for this, then we'll simply get an ID Token back which we cannot use to request
			// additional data of the user. We need to get an authorization code reponse (I'm not sure what the 
			// string value for that is but if we don't specify then it's the default). 
			ResponseType = "id_token",

			// The PolicyConfigurationManager takes care of getting the correct Azure AD authentication
			// endpoints from the OpenID Connect metadata endpoint.  It is included in the PolicyAuthHelpers folder.
			// The first parameter is the metadata URL of your B2C directory
			// The second parameter is an array of the policies that your app will use.
			ConfigurationManager = new PolicyConfigurationManager(
				string.Format(CultureInfo.InvariantCulture, AADInstance, tenant, "/v2.0", OIDCMetadataSuffix),
				new string[] { signUpPolicyId, signInPolicyId, userProfilePolicyId }),

			// This piece is optional - it is used for displaying the user's name in the navigation bar.
			TokenValidationParameters = new TokenValidationParameters
			{
				NameClaimType = "name",
			},

			SignInAsAuthenticationType = Umbraco.Core.Constants.Security.BackOfficeExternalAuthenticationType
		};

		adOptions.SetChallengeResultCallback(context => new AuthenticationProperties(
			new Dictionary<string, string>
			{
				{UmbracoADAuthExtensions.PolicyKey, signInPolicyId}
			})
		{
			RedirectUri = "/Umbraco",
		});
		
		var orig = adOptions.AuthenticationType;
		adOptions.ForUmbracoBackOffice(style, icon);
		adOptions.AuthenticationType = orig;

		adOptions.Caption = caption;

		//NOTE: This needs to be set after the ForUmbracoBackOffice
		// this needs to be set to what AD returns otherwise you cannot unlink an account
		adOptions.AuthenticationType = string.Format(
			CultureInfo.InvariantCulture,
			"https://login.microsoftonline.com/{0}/v2.0/",
			//Not sure where this comes from! ... perhaps 'issuerId', but i don't know where to find this,
			// i just know this based on the response we get from B2C
			"ae25bf5e-871e-454a-a1b6-a3560a09ec5e");

		//This will auto-create users based on the authenticated user if they are new
		//NOTE: This needs to be set after the explicit auth type is set
		adOptions.SetExternalSignInAutoLinkOptions(new ExternalSignInAutoLinkOptions(autoLinkExternalAccount: true));

		app.UseOpenIdConnectAuthentication(adOptions);            
	}
Ejemplo n.º 5
0
        /// <summary>
        ///     Configure ActiveDirectory sign-in
        /// </summary>
        /// <param name="app"></param>
        /// <param name="tenant">
        ///     Your tenant ID i.e. YOURDIRECTORYNAME.onmicrosoft.com OR this could be the GUID of your tenant ID
        /// </param>
        /// <param name="clientId">
        ///     Also known as the Application Id in the azure portal
        /// </param>
        /// <param name="postLoginRedirectUri">
        ///     The URL that will be redirected to after login is successful, example: http://mydomain.com/umbraco/;
        /// </param>
        /// <param name="issuerId">
        ///     This is the "Issuer Id" for you Azure AD application. This is a GUID value of your tenant ID.
        ///     If this value is not set correctly then accounts won't be able to be detected
        ///     for un-linking in the back office.
        /// </param>
        /// <param name="caption"></param>
        /// <param name="style"></param>
        /// <param name="icon"></param>
        /// <remarks>
        ///     ActiveDirectory account documentation for ASP.Net Identity can be found:
        ///     https://github.com/AzureADSamples/WebApp-WebAPI-OpenIDConnect-DotNet
        /// </remarks>
        public static void ConfigureBackOfficeAzureActiveDirectoryAuth(this IAppBuilder app,
                                                                       string tenant, string clientId, string postLoginRedirectUri, Guid issuerId,
                                                                       string caption = "Active Directory", string style = "btn-microsoft", string icon = "fa-windows")
        {
            var authority = string.Format(
                CultureInfo.InvariantCulture,
                "https://login.windows.net/{0}",
                tenant);

            var adOptions = new OpenIdConnectAuthenticationOptions
            {
                AuthenticationType = Constants.Security.BackOfficeExternalAuthenticationType,
                ClientId           = clientId,
                Authority          = authority,
                RedirectUri        = postLoginRedirectUri,
                Notifications      = new OpenIdConnectAuthenticationNotifications
                {
                    AuthorizationCodeReceived = async context =>
                    {
                        var userService = Current.Services.UserService;

                        var email       = context.JwtSecurityToken.Claims.First(x => x.Type.Equals("unique_name")).Value;
                        var issuer      = context.JwtSecurityToken.Claims.First(x => x.Type.Equals("iss")).Value;
                        var providerKey = context.JwtSecurityToken.Claims.First(x => x.Type.Equals("sub")).Value;
                        var userManager = context.OwinContext.GetUserManager <BackOfficeUserManager>();

                        var user = userService.GetByEmail(email);

                        if (user == null)
                        {
                            Log.Logger.Error($"The user {email} does not exist in Umbraco.");
                            return;
                        }

                        var identity = await userManager.FindByEmailAsync(email);

                        var identityClaims = await userManager.GenerateUserIdentityAsync(identity);

                        context.OwinContext.Authentication.SignIn(identityClaims);

                        //if (identity.Logins.All(x => {
                        //    return !x.ProviderKey.Equals(providerKey);
                        //}))
                        //{
                        //    identity.Logins.Add(new IdentityUserLogin(issuer, providerKey, user.Id));
                        //    await userManager.UpdateAsync(identity);
                        //}
                    }
                }
            };

            adOptions.ForUmbracoBackOffice(style, icon);
            adOptions.Caption = caption;
            //adOptions.AuthenticationType = string.Format(
            //    CultureInfo.InvariantCulture,
            //    "https://sts.windows.net/{0}/",
            //    issuerId);

            app.UseOpenIdConnectAuthentication(adOptions);

            adOptions.SetExternalSignInAutoLinkOptions(new ExternalSignInAutoLinkOptions(true));
        }