Solr NonRepeatableRequestException in save action - solr

I have configured Spring data solr 1.5.4 to use Apache Solr 5.2.1 and this is my configuration:
#Bean
public SolrTemplate solrTemplate() {
return new SolrTemplate(solrServerFactory());
}
#Bean
public SolrServerFactory solrServerFactory() {
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password);
return new HttpSolrServerFactory(solrServer(), "", credentials, "BASIC");
}
#Bean
public SolrServer solrServer() {
ModifiableSolrParams params = new ModifiableSolrParams();
params.set(HttpClientUtil.PROP_ALLOW_COMPRESSION, true);
params.set(HttpClientUtil.PROP_BASIC_AUTH_USER, username);
params.set(HttpClientUtil.PROP_BASIC_AUTH_PASS, password);
params.set(HttpClientUtil.PROP_CONNECTION_TIMEOUT, 12345);
params.set(HttpClientUtil.PROP_FOLLOW_REDIRECTS, true);
params.set(HttpClientUtil.PROP_MAX_CONNECTIONS, 22345);
params.set(HttpClientUtil.PROP_MAX_CONNECTIONS_PER_HOST, 32345);
params.set(HttpClientUtil.PROP_SO_TIMEOUT, 42345);
params.set(HttpClientUtil.PROP_USE_RETRY, false);
HttpClient httpClient = HttpClientUtil.createClient(params);
HttpSolrServer httpSolrServer = new HttpSolrServer("http://" + host + ":" + port + "/solr/", httpClient);
return httpSolrServer;
}
but when I want to save the document, this exception occurs:
14:28:45,863 Caused by: org.apache.http.client.NonRepeatableRequestException: Cannot retry request with a non-repeatable request entity.
14:28:45,863 at org.apache.http.impl.client.DefaultRequestDirector.tryExecute(DefaultRequestDirector.java:660)
14:28:45,863 at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:486)
14:28:45,863 at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:863)
Please help me.

Until this is fixed, implement PreemptiveAuthInterceptor and addRequestInterceptor before createClient
Sample is available at PreemptiveAuthInterceptor.java
e.g.
ModifiableSolrParams params = new ModifiableSolrParams();
params.add(HttpClientUtil.PROP_BASIC_AUTH_USER, uname);
params.add(HttpClientUtil.PROP_BASIC_AUTH_PASS, pwd);
params.add(HttpClientUtil.PROP_BASIC_AUTH_PASS, pwd);
HttpClientUtil.addRequestInterceptor(new PreemptiveAuthInterceptor());
CloseableHttpClient httpclient = HttpClientUtil.createClient(params);

Related

Change default download location on Edge chromium

I would like to ask if someone has tried to change the default download location on Microsoft Edge Chromium driver using selenium 3.X.
On Chrome browser, we could use something like this
HashMap<String, Object> chromePrefs = new HashMap<String, Object>();
chromePrefs.put("download.default_directory", savePAth);
chromePrefs.put("prompt_for_download", false);
options.setExperimentalOption("prefs", chromePrefs);
Info:
Microsoft Edge Browser version: 80.0.361.66 (Official build) (64-bit)
Thanks in Advance
Try using the following setup (Java Bindings):
public WebDriver newDriver() {
try {
EnvironmentVariables vars = SystemEnvironmentVariables.createEnvironmentVariables();
String version = vars.getProperty("webdriver.edgedriver.version");
WebDriverManager.edgedriver().version(version).setup();
EdgeOptions options = new EdgeOptions();
EdgeDriverService edgeDriverService = EdgeDriverService.createDefaultService();
EdgeDriver edgeDriver = new EdgeDriver(edgeDriverService, options);
final String downloadPath = ${your path}
//************* Enable downloading files / set path *******************
Map<String, Object> commandParams = new HashMap<>();
commandParams.put("cmd", "Page.setDownloadBehavior");
Map<String, String> params = new HashMap<>();
params.put("behavior", "allow");
params.put("downloadPath", downloadPath);
commandParams.put("params", params);
ObjectMapper objectMapper = new ObjectMapper();
HttpClient httpClient = HttpClientBuilder.create().build();
String command = objectMapper.writeValueAsString(commandParams);
String u = edgeDriverService.getUrl().toString() + "/session/" + edgeDriver.getSessionId() + "/chromium/send_command";
HttpPost request = new HttpPost(u);
request.addHeader("content-type", "application/json");
request.setEntity(new StringEntity(command));
httpClient.execute(request);
return edgeDriver;
} catch (Exception e) {
throw new Error(e);
}
}
I was able to download files to the desired path using this snippet. Source here

dotnet-core WebApp and multiple web api's access tokens using AzureB2C, MSAL

I have setup authentication/authorization for WebApp and Api and its working fine. The problem is when I have to introduce additional Api's which will be called from WebAPP.
The limitation is that you cannot ask a token with scopes mixing Web apis in one call. This is a limitation of the service (AAD), not of the library.
you have to ask a token for https://{tenant}.onmicrosoft.com/api1/read
and then you can acquire a token silently for https://{tenant}.onmicrosoft.com/api2/read as those are two different APIS.
I learned more about this from SO here and here
Since there is no full example other than couple of lines of code, I'm trying to find best way of implementing this solution.
Currently I have setup Authentication in Startup
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
services.AddAzureAdB2C(options => Configuration.Bind("AzureAdB2C", options)).AddCookie();
AddAzureAdB2C is an customized extension method from Samples.
public static AuthenticationBuilder AddAzureAdB2C(this AuthenticationBuilder builder, Action<AzureAdB2COptions> configureOptions)
{
builder.Services.Configure(configureOptions);
builder.Services.AddSingleton<IConfigureOptions<OpenIdConnectOptions>, OpenIdConnectOptionsSetup>();
builder.AddOpenIdConnect();
return builder;
}
public class OpenIdConnectOptionsSetup : IConfigureNamedOptions<OpenIdConnectOptions>
{
public void Configure(OpenIdConnectOptions options)
{
options.ClientId = AzureAdB2COptions.ClientId;
options.Authority = AzureAdB2COptions.Authority;
options.UseTokenLifetime = true;
options.TokenValidationParameters = new TokenValidationParameters() { NameClaimType = "name" };
options.Events = new OpenIdConnectEvents()
{
OnRedirectToIdentityProvider = OnRedirectToIdentityProvider,
OnRemoteFailure = OnRemoteFailure,
OnAuthorizationCodeReceived = OnAuthorizationCodeReceived
};
}
public Task OnRedirectToIdentityProvider(RedirectContext context)
{
var defaultPolicy = AzureAdB2COptions.DefaultPolicy;
if (context.Properties.Items.TryGetValue(AzureAdB2COptions.PolicyAuthenticationProperty, out var policy) &&
!policy.Equals(defaultPolicy))
{
context.ProtocolMessage.Scope = OpenIdConnectScope.OpenIdProfile;
context.ProtocolMessage.ResponseType = OpenIdConnectResponseType.IdToken;
context.ProtocolMessage.IssuerAddress = context.ProtocolMessage.IssuerAddress.ToLower().Replace(defaultPolicy.ToLower(), policy.ToLower());
context.Properties.Items.Remove(AzureAdB2COptions.PolicyAuthenticationProperty);
}
else if (!string.IsNullOrEmpty(AzureAdB2COptions.ApiUrl))
{
context.ProtocolMessage.Scope += $" offline_access {AzureAdB2COptions.ApiScopes}";
context.ProtocolMessage.ResponseType = OpenIdConnectResponseType.CodeIdToken;
}
return Task.FromResult(0);
}
}
I guess the scope has to be set on this line for each API but this is part of pipeline.(in else if part of OnRedirectToIdentityProvide method above)
context.ProtocolMessage.Scope += $" offline_access {AzureAdB2COptions.ApiScopes}";
Following are api client configuration
services.AddHttpClient<IApiClient1, ApiClient1>()
.AddHttpMessageHandler<API1AccessTokenHandler>();
services.AddHttpClient<IApiClient2, ApiClient2>()
.AddHttpMessageHandler<API2AccessTokenHandler>();
Following is the code for acquiring token silently for API1.
public class API1AccessTokenHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
IConfidentialClientApplication publicClientApplication = null;
try
{
// Retrieve the token with the specified scopes
scopes = AzureAdB2COptions.ApiScopes.Split(' ');
string signedInUserID = _httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;
publicClientApplication = ConfidentialClientApplicationBuilder.Create(AzureAdB2COptions.ClientId)
.WithRedirectUri(AzureAdB2COptions.RedirectUri)
.WithClientSecret(AzureAdB2COptions.ClientSecret)
.WithB2CAuthority(AzureAdB2COptions.Authority)
.Build();
new MSALStaticCache(signedInUserID, _httpContextAccessor.HttpContext).EnablePersistence(publicClientApplication.UserTokenCache);
var accounts = await publicClientApplication.GetAccountsAsync();
result = await publicClientApplication.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
.ExecuteAsync();
}
catch (MsalUiRequiredException ex)
{
}
if (result.AccessToken== null)
{
throw new Exception();
}
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
return await base.SendAsync(request, cancellationToken);
}
}
Following is the code for acquiring token silently for API2, API2AccessTokenHandler.
public class API2AccessTokenHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
IConfidentialClientApplication publicClientApplication = null;
try
{
// Retrieve the token with the specified scopes
scopes = Constants.Api2Scopes.Split(' ');
string signedInUserID = _httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;
publicClientApplication = ConfidentialClientApplicationBuilder.Create(AzureAdB2COptions.ClientId)
.WithRedirectUri(AzureAdB2COptions.RedirectUri)
.WithClientSecret(AzureAdB2COptions.ClientSecret)
.WithB2CAuthority(AzureAdB2COptions.Authority)
.Build();
new MSALStaticCache(signedInUserID, _httpContextAccessor.HttpContext).EnablePersistence(publicClientApplication.UserTokenCache);
var accounts = await publicClientApplication.GetAccountsAsync();
result = await publicClientApplication.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
.ExecuteAsync();
}
catch (MsalUiRequiredException ex)
{
}
if (result.AccessToken== null)
{
throw new Exception();
}
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
return await base.SendAsync(request, cancellationToken);
}
}
Passing the scope while acquiring the token did not help. The token
is always null.
The account always have scope for Api1 but not for
Api2.
The scope of APi1 is added from the AzureB2COptions.ApiScope
as part of the ServiceCollection pipeline code in Startup.cs
I guess having separate calls to Acquire token is not helping in case of Api2 because scope is being set for Api1 in Startup.cs.
Please provide your valuable suggestions along with code samples.
UPDATE:
I'm looking something similar to WithExtraScopeToConsent which is designed for IPublicClientApplication.AcquireTokenInteractive. I need similar extension for ConfidentialClientApplicationBuilder to be used for AcquireTokenByAuthorizationCode
cca.AcquireTokenByAuthorizationCode(AzureAdB2COptions.ApiScopes.Split(' '), code)
.WithExtraScopeToConsent(additionalScopeForAPi2)
.ExecuteAsync();
Yes, we can have multiple scopes for same api not multiple scopes from different Apis.
In this sample, we retrieve the token with the specified scopes.
// Retrieve the token with the specified scopes
var scope = new string[] { api1_scope };
IConfidentialClientApplication cca = MsalAppBuilder.BuildConfidentialClientApplication();
var accounts = await cca.GetAccountsAsync();
AuthenticationResult result = await cca.AcquireTokenSilent(scope, accounts.FirstOrDefault()).ExecuteAsync();
var accessToken=result.AccessToken;
You can get the accessToken with different api scope.
// Retrieve the token with the specified scopes
var scope = new string[] { api2_scope };
IConfidentialClientApplication cca = MsalAppBuilder.BuildConfidentialClientApplication();
var accounts = await cca.GetAccountsAsync();
AuthenticationResult result = await cca.AcquireTokenSilent(scope, accounts.FirstOrDefault()).ExecuteAsync();
var accessToken=result.AccessToken;

SAML2.0 Access token using 'itfoxtec-identity-saml2'

I am trying to use your Nuget package for dotnet core and I get little bit success also I can login to SAML identity providers like Onelogin,Okta and I got loggin user information also But I am confuse while generating access token(Bearer token to call APIs of SAML identity providers). How will I get that token?
I can see securitytoken object in saml2AuthnResponse but don’t know how to that token and in that object security key and singin key is null.
I am totally new to this so may be I misunderstand something.
Please help me.
[Route("AssertionConsumerService")]
public async Task<IActionResult> AssertionConsumerService()
{
var binding = new Saml2PostBinding();
var saml2AuthnResponse = new Saml2AuthnResponse(config);
binding.ReadSamlResponse(Request.ToGenericHttpRequest(), saml2AuthnResponse);
if (saml2AuthnResponse.Status != Saml2StatusCodes.Success)
{
throw new AuthenticationException($"SAML Response status: {saml2AuthnResponse.Status}");
}
binding.Unbind(Request.ToGenericHttpRequest(), saml2AuthnResponse);
await saml2AuthnResponse.CreateSession(HttpContext, claimsTransform: (claimsPrincipal) => ClaimsTransform.Transform(claimsPrincipal));
var relayStateQuery = binding.GetRelayStateQuery();
var returnUrl = relayStateQuery.ContainsKey(relayStateReturnUrl) ? relayStateQuery[relayStateReturnUrl] : Url.Content("~/");
return Redirect(returnUrl);
}
You can get access to the SAML 2.0 token as a XML string by setting Saml2Configuration.SaveBootstrapContext = true in appsettings.json:
...
"Saml2": {
"SaveBootstrapContext": true,
"IdPMetadata": "https://localhost:44305/metadata",
"Issuer": "itfoxtec-testwebappcore",
...
}
Alternatively you can set the configuration in code:
config.SaveBootstrapContext = true;
Then you can read the SAML 2.0 token as a XML string in the saml2AuthnResponse.ClaimsIdentity.BootstrapContext:
public async Task<IActionResult> AssertionConsumerService()
{
var binding = new Saml2PostBinding();
var saml2AuthnResponse = new Saml2AuthnResponse(config);
binding.ReadSamlResponse(Request.ToGenericHttpRequest(), saml2AuthnResponse);
if (saml2AuthnResponse.Status != Saml2StatusCodes.Success)
{
throw new AuthenticationException($"SAML Response status: {saml2AuthnResponse.Status}");
}
binding.Unbind(Request.ToGenericHttpRequest(), saml2AuthnResponse);
await saml2AuthnResponse.CreateSession(HttpContext, claimsTransform: (claimsPrincipal) => ClaimsTransform.Transform(claimsPrincipal));
var samlTokenXml = saml2AuthnResponse.ClaimsIdentity.BootstrapContext as string;
var relayStateQuery = binding.GetRelayStateQuery();
var returnUrl = relayStateQuery.ContainsKey(relayStateReturnUrl) ? relayStateQuery[relayStateReturnUrl] : Url.Content("~/");
return Redirect(returnUrl);
}

Why i am getting "Bad Request" error while using Gmail Api?

i'm working wpf application.I want to delete email from all account in domain.
I'm using service account wide delegetion for this.
i also use here for authentication and other methods. I gave all permission for my admin account.
public GmailService GetService()
{ var certificate = new X509Certificate2(#"xxxxxxxxxxxx-
fc9fcdc65959.p12", "notasecret", X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[] { GmailService.Scope.MailGoogleCom }
}.FromCertificate(certificate));
GmailService service = new GmailService(new
BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = AppName,
});
return service;
}
List Function is below.
public static List<Google.Apis.Gmail.v1.Data.Message>
ListMessages(GmailService service, String userId, String query)
{
List<Google.Apis.Gmail.v1.Data.Message> result = new
List<Google.Apis.Gmail.v1.Data.Message>();
UsersResource.MessagesResource.ListRequest request =
service.Users.Messages.List(userId);
request.Q = query;
do
{
try
{
ListMessagesResponse response = request.Execute();
result.AddRange(response.Messages);
request.PageToken = response.NextPageToken;
}
catch (Exception e)
{
Console.WriteLine("An error occurred: " + e.Message);
}
} while (!String.IsNullOrEmpty(request.PageToken));
return result;
}
When i try to list all emails, i'm getting this error.
"Google.Apis.Requests.RequestError
Bad Request [400]
Errors [
Message[Bad Request] Location[ - ] Reason[failedPrecondition]
Domain[global]
]"
İs anyone there to help me?
You need to add a user account like:
ServiceAccountCredential.Initializer constructor =
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
user = user_email;
Scopes = new[] { GmailService.Scope.MailGoogleCom }
}.FromCertificate(certificate));

Hack to upload a file from Java backend to a remote server over HTTP using Rest API.

My file resides on some location on my machine say C://users//abc.txt and i want to write a java program to transfer this file using REST API over HTTP. I used MockHttpServelet Request to create the request, but somehow i am unable to transfer the file
Use HttpClient:
String url = "http://localhost:8080/upload"; // Replace with your target 'REST API' url
String filePath = "C://users//abc.txt";
CloseableHttpClient httpClient = HttpClients.createDefault();
try {
HttpPost httpPost = new HttpPost(url);
FileEntity entity = new FileEntity(new File(filePath), ContentType.TEXT_PLAIN);
httpPost.setEntity(entity);
HttpResponse httpResponse = httpClient.execute(httpPost);
System.out.println(httpResponse.getStatusLine().getStatusCode()); // Check HTTP code
} finally {
httpClient.close();
}
With Authentication:
String url = "http://localhost:8080/upload"; // Replace with your target 'REST API' url
String filePath = "C://users//abc.txt";
String username = "username"; // Replace with your username
String password = "password"; // Replace with your password
RequestConfig requestConfig =
RequestConfig.custom().
setAuthenticationEnable(true).
build();
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(
AuthScope.ANY,
new UsernamePasswordCredential(username, password));
CloseableHttpClient httpClient =
HttpClients.custom().
setDefaultRequestConfig(requestConfig).
setDefaultCredentialsProvider(credentialsProvider).
build();
try {
HttpPost httpPost = new HttpPost(url);
FileEntity entity = new FileEntity(new File(filePath), ContentType.TEXT_PLAIN);
httpPost.setEntity(entity);
HttpResponse httpResponse = httpClient.execute(httpPost);
System.out.println(httpResponse.getStatusLine().getStatusCode()); // Check HTTP code
} finally {
httpClient.close();
}
String location="C:\\Usersabc.img";
Path path = Paths.get(location);
String name=location.substring(location.lastIndexOf("\\")+1);
MultipartEntity multipart= new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
try {
multipart.addPart("image", new ByteArrayBody(Files.readAllBytes(path), ContentType.APPLICATION_OCTET_STREAM.getMimeType(),name));
}
catch (IOException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
}

Resources