Right now I am working with the application which automatically logs in user through microsoft account after user enters the credentials once. This is how I am trying to call the microsoft login:
public partial class Startup
{
// Load configuration settings from PrivateSettings.config
private static string appId = ConfigurationManager.AppSettings["ida:AppId"];
private static string appSecret = ConfigurationManager.AppSettings["ida:AppSecret"];
private static string redirectUri = ConfigurationManager.AppSettings["ida:RedirectUri"];
private static string tenantId = ConfigurationManager.AppSettings["ida:tenantId"];
private static string aadInstance = ConfigurationManager.AppSettings["ida:AADInstance"];
public static string authority = aadInstance + tenantId;
public void Configuration(IAppBuilder app)
{
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=316888
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseKentorOwinCookieSaver();
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = appId,
Authority = authority,
RedirectUri = redirectUri,
TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = OnAuthenticationFailedAsync,
AuthorizationCodeReceived = OnAuthorizationCodeReceivedAsync
}
}
);
}
private static Task OnAuthenticationFailedAsync(AuthenticationFailedNotification<OpenIdConnectMessage,
OpenIdConnectAuthenticationOptions> notification)
{
notification.HandleResponse();
string redirect = $"Home/Error?message={notification.Exception.Message}";
if (notification.ProtocolMessage != null && !string.IsNullOrEmpty(notification.ProtocolMessage.ErrorDescription))
{
redirect += $"&debug={notification.ProtocolMessage.ErrorDescription}";
}
notification.Response.Redirect(redirect);
return Task.FromResult(0);
}
private async Task OnAuthorizationCodeReceivedAsync(AuthorizationCodeReceivedNotification notification)
{
var idClient = ConfidentialClientApplicationBuilder.Create(appId)
.WithRedirectUri(redirectUri)
.WithTenantId(tenantId)
.WithClientSecret(appSecret)
.Build();
string email = string.Empty;
try
{
string[] scopes = null;
var result = await idClient.AcquireTokenByAuthorizationCode(
scopes, notification.Code).ExecuteAsync();
email = await GraphHelper.GetUserDetailsAsync(result.AccessToken);
var account = await idClient.GetAccountAsync(result.Account.HomeAccountId.Identifier);
await idClient.RemoveAsync(account);//
}
catch (MsalException ex)
{
System.Diagnostics.Trace.TraceError(ex.Message);
}
notification.HandleResponse();
notification.Response.Redirect($"Account/SignInAzureEmailAsync?email={email}");
}
}
<add key="ida:AADInstance" value="https://login.microsoftonline.com/" />
I read this Microsoft document where is suggested me to use prompt=login which forces user to login every time they click on login button. I couldn't figure out how to apply this modification in my link. Any suggestions please?
You can use RedirectToIdentityProvider function to configure the prompt property
Notifications = new OpenIdConnectAuthenticationNotifications()
{
RedirectToIdentityProvider = context =>
{
context.ProtocolMessage.SetParameter("prompt", "login");
return Task.FromResult(0);
}
}
};
I want to configure ADFS endpoints in my asp.net app at runtime.
There is a problem: if I declare single callback method for multiple endpoints then I have exception:
Microsoft.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException: IDX10501: Signature validation failed. Unable to match keys:
kid: '[PII is hidden]',
token: '[PII is hidden]'.
If I will hard-code callbacks (Wreply) for each endpoint then all works, but this is not my case.
Startup.cs
public class Startup
{
public void Configuration(IAppBuilder app)
{
var federationEndpoints = Service.ListActiveFederationEndpoints();
if (federationEndpoints.Any())
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
var endpointOptions = new List<WsFederationAuthenticationOptions>();
foreach (var endpoint in federationEndpoints)
{
string metadata = endpoint.ServerUri;
string wtrealm = endpoint.RelyingPartyIdentifier;
endpointOptions.Add(new WsFederationAuthenticationOptions
{
Wtrealm = wtrealm,
MetadataAddress = metadata,
AuthenticationType = endpoint.Name
});
}
app.Map("/FederationAuth", configuration =>
{
endpointOptions.ForEach(o => app.UseWsFederationAuthentication(o));
});
}
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Name;
}
}
Login and common callback (Wreply) in FederationAuthController
[AllowAnonymous]
public void ExternalLogin(string endpointName)
{
var ctx = Request.GetOwinContext();
ctx.Authentication.Challenge(
new AuthenticationProperties { RedirectUri = Url.Action("LoginCallbackAdfs", "FederationAuth") },
endpointName);
}
public ActionResult LoginCallbackAdfs()
{
var ctx = System.Web.HttpContext.Current;
var claimsIdentity = User.Identity as ClaimsIdentity;
var sessionIdentity = Service.LoginByClaims(claimsIdentity);
return this.RedirectToAction("Index", "SinglePage");
}
I've read many answers for configuring hard-coded multiple ADFS endpoints in Web.config but is there possibility to configure enpoints at runtime?
Thank you!
Wreply should be unique and set for each federation middleware during pipeline building. I made unique Wreply including endpoint name as callback parameter.
Startup.cs
public void Configuration(IAppBuilder app)
{
var federationChannels = Service.GetFederationChannels();
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.SetDefaultSignInAsAuthenticationType(CookieAuth.AuthenticationType);
foreach (var channel in federationChannels)
{
var metadata = channel.Metadata;
var wtrealm = channel.Wtrealm ;
var host = GetServerAddress();
var wreply = $"{host}FederationLogin/channel={channel.Id}";
app.UseWsFederationAuthentication(new WsFederationAuthenticationOptions
{
Wtrealm = wtrealm,
MetadataAddress = metadata,
AuthenticationType = channel.Id,
Wreply = wreply,
SignOutWreply = host
});
}
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Name;
}
Controller
public ActionResult FederationLogin(string channel)
{
....
HttpContext.GetOwinContext().Authentication.Challenge(new AuthenticationProperties(), channel);
....
}
I have created integrator key and private/public key in docusign sandbox.
When I am trying to call api,it is giving me error.
My code is like this:
public class DocuSignExample1 {
private static final String IntegratorKey = "10048d4c-0549-434e-b224-4805b36b69e1";
private static final String UserId = "ef27e777-c6fc-4385-91ce-63dafab5385b";
private static final String privateKeyFullPath = System.getProperty("user.dir") + "/src/test/keys/docusign_private_key2.txt";
private static final String Recipient = "xxx#gmail.com";
private static final String SignTest1File = "/src/test/docs/SignTest1.pdf";
private static final String BaseUrl = "https://demo.docusign.net/restapi";
public static void main(String[] args) {
byte[] fileBytes = null;
try {
String currentDir = System.getProperty("user.dir");
Path path = Paths.get(currentDir + SignTest1File);
fileBytes = Files.readAllBytes(path);
} catch (IOException ioExcp) {
ioExcp.printStackTrace();
}
EnvelopeDefinition envDef = new EnvelopeDefinition();
envDef.setEmailSubject("Please Sign My Sample Document");
envDef.setEmailBlurb("Hello, Please Sign My Sample Document.");
Document doc = new Document();
String base64Doc = Base64.encodeToString(fileBytes, false);
doc.setDocumentBase64(base64Doc);
doc.setName("TestFile.pdf");
doc.setDocumentId("1");
List<Document> docs = new ArrayList<Document>();
docs.add(doc);
envDef.setDocuments(docs);
Signer signer = new Signer();
signer.setEmail(Recipient);
signer.setName("Sanjay");
signer.setRecipientId("1");
envDef.setRecipients(new Recipients());
envDef.getRecipients().setSigners(new ArrayList<Signer>());
envDef.getRecipients().getSigners().add(signer);
envDef.setStatus("sent");
ApiClient apiClient = new ApiClient(BaseUrl);
try {
byte[] privateKeyBytes = null;
try {
privateKeyBytes = Files.readAllBytes(Paths.get(privateKeyFullPath));
} catch (IOException e) {
e.printStackTrace();
}
if (privateKeyBytes == null)
return;
java.util.List<String> scopes = new ArrayList<String>();
scopes.add(OAuth.Scope_SIGNATURE);
OAuth.OAuthToken oAuthToken = apiClient.requestJWTUserToken(IntegratorKey, UserId, scopes, privateKeyBytes,
3600);
apiClient.setAccessToken(oAuthToken.getAccessToken(), oAuthToken.getExpiresIn());
UserInfo userInfo = apiClient.getUserInfo(oAuthToken.getAccessToken());
apiClient.setBasePath(userInfo.getAccounts().get(0).getBaseUri() + "/restapi");
Configuration.setDefaultApiClient(apiClient);
String accountId = userInfo.getAccounts().get(0).getAccountId();
EnvelopesApi envelopesApi = new EnvelopesApi();
EnvelopeSummary envelopeSummary = envelopesApi.createEnvelope(accountId, envDef);
System.out.println("EnvelopeSummary: " + envelopeSummary);
} catch (ApiException ex) {
ex.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
In above code I am just changing my account key,but not working.
I have created project with example.
Here DocusignExample.java is working but DocusignExample1.java
is not working.
https://gitlab.com/sanju24689/docusign
For DocusignExample,I have taken reference(key) from docusign java sdk(https://github.com/docusign/docusign-java-client/blob/master/src/test/java/SdkUnitTests.java)
With that reference i have created my code and just change integratory key,api username and private key.
It's giving me error like "com.docusign.esign.client.ApiException: Error while requesting an access token: POST https://account-d.docusign.com/oauth/token returned a response status of 400 Bad Request"
So you have a working example but then when you change the integration key the example stops working?
Sounds like a problem with your settings: check that you're using the right RSA Private key with the right Integration Key (IK).
Also check that the IK does NOT have "Mobile app" checked.
We've got some Azure Functions defined in a class using [FunctionName] attributes from the WebJobs SDK. There are several functions in the class and they all need access to secrets stored in an Azure KeyVault. The problem is that we have many hundreds invocations of the functions a minute, and since each one is making a call to the KeyVault, KeyVault is failing with a message saying something like, "Too many connections. Usually only 10 connections are allowed."
#crandycodes (Chris Anderson) on Twitter suggested making the KeyVaultClient static. However, the constructor we're using for the KeyVaultClient requires a delegate function for the constructor, and you can't use a static method as a delegate. So how can we make the KeyVaultClient static? That should allow the functions to share the client, reducing the number of sockets.
Here's our KeyVaultHelper class:
public class KeyVaultHelper
{
public string ClientId { get; protected set; }
public string ClientSecret { get; protected set; }
public string VaultUrl { get; protected set; }
public KeyVaultHelper(string clientId, string secret, string vaultName = null)
{
ClientId = clientId;
ClientSecret = secret;
VaultUrl = vaultName == null ? null : $"https://{vaultName}.vault.azure.net/";
}
public async Task<string> GetSecretAsync(string key)
{
try
{
using (var client = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(GetAccessTokenAsync),
new HttpClient()))
{
var secret = await client.GetSecretAsync(VaultUrl, key);
return secret.Value;
}
}
catch (Exception ex)
{
throw new ApplicationException($"Could not get value for secret {key}", ex);
}
}
public async Task<string> GetAccessTokenAsync(string authority, string resource, string scope)
{
var authContext = new AuthenticationContext(authority, TokenCache.DefaultShared);
var clientCred = new ClientCredential(ClientId, ClientSecret);
var result = await authContext.AcquireTokenAsync(resource, clientCred);
if (result == null)
{
throw new InvalidOperationException("Could not get token for vault");
}
return result.AccessToken;
}
}
Here's how we reference the class from our functions:
public class ProcessorEntryPoint
{
[FunctionName("MyFuncA")]
public static async Task ProcessA(
[QueueTrigger("queue-a", Connection = "queues")]ProcessMessage msg,
TraceWriter log
)
{
var keyVaultHelper = new KeyVaultHelper(CloudConfigurationManager.GetSetting("ClientId"), CloudConfigurationManager.GetSetting("ClientSecret"),
CloudConfigurationManager.GetSetting("VaultName"));
var secret = keyVaultHelper.GetSecretAsync("mysecretkey");
// do a stuff
}
[FunctionName("MyFuncB")]
public static async Task ProcessB(
[QueueTrigger("queue-b", Connection = "queues")]ProcessMessage msg,
TraceWriter log
)
{
var keyVaultHelper = new KeyVaultHelper(CloudConfigurationManager.GetSetting("ClientId"), CloudConfigurationManager.GetSetting("ClientSecret"),
CloudConfigurationManager.GetSetting("VaultName"));
var secret = keyVaultHelper.GetSecretAsync("mysecretkey");
// do b stuff
}
}
We could make the KeyVaultHelper class static, but that in turn would need a static KeyVaultClient object to avoid creating a new connection on each function call - so how do we do that or is there another solution? We can't believe that functions that require KeyVault access are not scalable!?
You can use a memory cache and set the length of the caching to a certain time which is acceptable in your scenario. In the following case you have a sliding expiration, you can also use a absolute expiration, depending on when the secrets change.
public async Task<string> GetSecretAsync(string key)
{
MemoryCache memoryCache = MemoryCache.Default;
string mkey = VaultUrl + "_" +key;
if (!memoryCache.Contains(mkey))
{
try
{
using (var client = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(GetAccessTokenAsync),
new HttpClient()))
{
memoryCache.Add(mkey, await client.GetSecretAsync(VaultUrl, key), new CacheItemPolicy() { SlidingExpiration = TimeSpan.FromHours(1) });
}
}
catch (Exception ex)
{
throw new ApplicationException($"Could not get value for secret {key}", ex);
}
return memoryCache[mkey] as string;
}
}
try the following changes in the helper:
public class KeyVaultHelper
{
public string ClientId { get; protected set; }
public string ClientSecret { get; protected set; }
public string VaultUrl { get; protected set; }
KeyVaultClient client = null;
public KeyVaultHelper(string clientId, string secret, string vaultName = null)
{
ClientId = clientId;
ClientSecret = secret;
VaultUrl = vaultName == null ? null : $"https://{vaultName}.vault.azure.net/";
client = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(GetAccessTokenAsync), new HttpClient());
}
public async Task<string> GetSecretAsync(string key)
{
try
{
if (client == null)
client = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(GetAccessTokenAsync), new HttpClient());
var secret = await client.GetSecretAsync(VaultUrl, key);
return secret.Value;
}
catch (Exception ex)
{
if (client != null)
{
client.Dispose();
client = null;
}
throw new ApplicationException($"Could not get value for secret {key}", ex);
}
}
public async Task<string> GetAccessTokenAsync(string authority, string resource, string scope)
{
var authContext = new AuthenticationContext(authority, TokenCache.DefaultShared);
var clientCred = new ClientCredential(ClientId, ClientSecret);
var result = await authContext.AcquireTokenAsync(resource, clientCred);
if (result == null)
{
throw new InvalidOperationException("Could not get token for vault");
}
return result.AccessToken;
}
}
now, the function can use a default static constructor to keep the client proxy:
public static class ProcessorEntryPoint
{
static KeyVaultHelper keyVaultHelper;
static ProcessorEntryPoint()
{
keyVaultHelper = new KeyVaultHelper(CloudConfigurationManager.GetSetting("ClientId"), CloudConfigurationManager.GetSetting("ClientSecret"), CloudConfigurationManager.GetSetting("VaultName"));
}
[FunctionName("MyFuncA")]
public static async Task ProcessA([QueueTrigger("queue-a", Connection = "queues")]ProcessMessage msg, TraceWriter log )
{
var secret = keyVaultHelper.GetSecretAsync("mysecretkey");
// do a stuff
}
[FunctionName("MyFuncB")]
public static async Task ProcessB([QueueTrigger("queue-b", Connection = "queues")]ProcessMessage msg, TraceWriter log )
{
var secret = keyVaultHelper.GetSecretAsync("mysecretkey");
// do b stuff
}
}
You don't actually want KeyVault to scale like that. It is protecting you from racking up unnecessary costs and slow behavior. All you need to do it save the secret for later use. I've created a static class for static instantiation.
public static class KeyVaultHelper
{
private static Dictionary<string, string> Cache = new Dictionary<string, string>();
public static async Task<string> GetSecretAsync(string secretIdentifier)
{
if (Cache.ContainsKey(secretIdentifier))
return Cache[secretIdentifier];
var kv = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(GetToken));
var secretValue = (await kv.GetSecretAsync(secretIdentifier)).Value;
Cache[secretIdentifier] = secretValue;
return secretValue;
}
private static async Task<string> GetToken(string authority, string resource, string scope)
{
var clientId = ConfigurationManager.AppSettings["ClientID"];
var clientSecret = ConfigurationManager.AppSettings["ClientSecret"];
var clientCred = new ClientCredential(clientId, clientSecret);
var authContext = new AuthenticationContext(authority);
AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCred);
if (result == null)
throw new InvalidOperationException("Failed to obtain the JWT token");
return result.AccessToken;
}
}
Now in your code, you can do something like this:
private static readonly string ConnectionString = KeyVaultHelper.GetSecretAsync(ConfigurationManager.AppSettings["SqlConnectionSecretUri"]).GetAwaiter().GetResult();
Now whenever you need your secret, it is immediately there.
NOTE: If Azure Functions ever shuts down the instance due to lack of use, the static goes away and is reloaded the next time the function is called. Or you can your own functionality to reload the statics.
I am using HttpClient and defaultHttpClient Methods in getInternetData function on android studi. but these methods are no longer part of the SDK 23. how can i overcome this problem.i have used dependencies in build.gradle too , but still error remains here. Kindly tell me are there any other methods to call.?
public class GetMethodEx {
public String getInternetData() throws Exception{
BufferedReader in = null;
String data = null;
try{
HttpClient client = new DefaultHttpClient();
URI website = new URI("http://api.twitter.com/1/statuses/public_timeline.json");
HttpGet request = new HttpGet();
request.setURI(website);
HttpResponse response = client.execute(request);
in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer sb = new StringBuffer("");
String l = "";
String nl = System.getProperty("line.separator");
while ((l = in.readLine()) !=null){
sb.append(l + nl);
}
in.close();
data = sb.toString();
return data;
}finally{
if (in != null){
try{
in.close();
return data;
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}