I am trying to write a SOLR client using SolrJ HttpSolrClient.
I have to use Basic Authentication.
The documentation for SolrJ HttpSolrClient says that there is:
protected ModifiableSolrParams invariantParams
and the description is:
Parameters that are added to every request regardless. This may be a place to add something like an authentication token.
Can someone who has used this before please tell me how to use the invariantParams for basic auth?
public class MySolrClient extends HttpSolrClient{
private String hostUrl;
private String userName;
private String password;
public CloudForgeProcurementSolrClient(final String hostUrl, final String userName, final String password) {
super(hostUrl);
this.hostUrl = hostUrl;
this.userName = userName;
this.password = password;
if (invariantParams == null) {
invariantParams = new ModifiableSolrParams();
}
// invariantParams.add(arg0, arg1);
}
}
What should be arg0 and arg1 be in my case.
Thanks in advance!
You can do something like
CredentialsProvider provider = new BasicCredentialsProvider();
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(
"myusername","mypassword");
provider.setCredentials(AuthScope.ANY, credentials);
HttpClient client = HttpClientBuilder.create().setDefaultCredentialsProvider(provider).build();
HttpSolrClient solrClient = new HttpSolrClient(solrCoreUrl, client);
you can use below code:
CredentialsProvider provider = new BasicCredentialsProvider();
UsernamePasswordCredentials credentials = new
UsernamePasswordCredentials(username,password);
provider.setCredentials(AuthScope.ANY, credentials);
HttpClient client = HttpClientBuilder.create().setDefaultCredentialsProvider(provider).build();
HttpSolrClient solrClient = new HttpSolrClient.Builder()
.withBaseSolrUrl(host)
.withHttpClient(client).build();
Related
I'm following Google's documentation, on how to create a JWT for a specific service account.
The document instructs on how to manually create a JWT, as well as how to compute the signing process, based on JWS guidelines.
I followed the exact procedure described by Google, but no matter what i do, the generated JWT cannot be validated by jwt.io, which fails with a Invalid Signature.
Follow the guidelines, i created the service account, and a specific key, which contains the Private Key details:
{
"type": "service_account",
"project_id": "myProject",
"private_key_id": "1212121212",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC5Cg7FW0NGwLeD\nrpc0r1Ayta23GxVw0KCA+d/TjSyuZ3lmKiObz9EGJpHSHbX4yrODA6FvYixUrAKm\nUSSMvFLUpYM2xoEgAKnwd6XVgdnjwk7wnIIsEdyjMCbews1orr6Ze+LIPkV2WF4d\nHSAqRqJrERR1Gb9gxKC/WQhMvCotp7zFTqLcUI3eUhR3tIgpLwZFpIxXZjOTwWoB\n6bWxOe39Suft1GYAR0prFcLmXtfw43B+9gVcMLOHBBTcxojBXkQ2bhjp7dGqvlUz\n3nO/1bqbzvd5I6bQif+tjLEceyIUbE/rJ6PgW9SVtfktrQIQQ9VGtAUya4IYSEL8\nJaXZxs6jAgMBAAECggEAFe1+3J0OYZcQPZb2AjSi+1oTm6GmWSJ6ssNpu9x8pq+f\nxPSfbaUjRGhTsCOnNIlzhnDACRQIOYHSJTrJFbMc2b2XdBPyqgPfdPNTf/QNtHOK\nqUbSwj2Ho6sJdYJ+QbaGOGgO8uM2QL+uFM3RHvwUiT2SlWHsukny3ATFUAVIYPUj\nxr0m6QKBgQDiH6vL1plGsIFVWR5M\nESsZdADubhDOtml6r81aKLXJPK9LeHwJOAgTFfZHJD4D4e7KSQfYlbf9tRE7c2PE\ntcj6BVrHdtYRqaXY+Q7BW2mXRb7IJKtVxZzljPY0HcDjpZ7UqXUB/sVbxT/zbt4B\n9lIegpLJyd6RpzYhjIDv8OIaTwKBgQDRfMLsTg0+nTzmmIurmD1IhdPa7KvhGMDn\nXSs0zRR4IRC2BCn5LHYYD4cgO+mmGWxcQZREQ220W3uXwRbSTJZT6ZtzP40AXx86\nTRop5NBZYDkdJ1t9qhi2aU//5mwn5ubC/42fBCwqmRXr0nOtLhKtEONRmGGyl7hk\nWXWII2z1bQKBgAMoNArVhTBSeIvLgbvIJZTmZLjvenaYX2KiH7jZhqg3mRoyUuvA2glpo9ARzB7ut\nR5LXq5GAwOBIzMhtZWTyE53O9jI5+8g/RB7WlUx\nsZt5bkf42zhsJwZnfV480Hx8GhnCnhGcTVjJbbN5AoGBAInRfNcLpgPtHWiQ5r9W\nANd+XDLpjIUQfh+0NaQeYPG7DM59oPRqUDs/BSp21nTmSnNC537H0OHlCScpmc7G\ncpj+/jtLIhTN0IwKosaH3mJpQ3AcUI7IooFKgYrC/bwCUQ5xX7CwqaOzTKf3MtX1\nngd7mPWTFkRDxCkCnvfUfcem\n-----END PRIVATE KEY-----\n",
"client_email": "test#email",
"client_id": "121212",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/myProject-dev.iam.gserviceaccount.com"
}
I'm using .net 5, and the .net implementation for manually creating and signing a JWT, would be:
private string GetToken()
{
var header = "{\"typ\":\"JWT\",\"alg\":\"RS256\",\"kid\":\"ed36c257c59ebabb47b456828a858aa5fcda12xx\"}";
var claims = "{\"sub\":\"10217931234509168826\",\"email\":\"test#email.com\",\"iss\":\"https:\\//accounts.google.com\",\"aud\":\"MyAudience",\"exp\":1665530643,\"iat\":1665527043}";
var b64header = Convert.ToBase64String(Encoding.UTF8.GetBytes(header))
.Replace('+', '-').Replace('/', '_').Replace("=", "");
var b64claims = Convert.ToBase64String(Encoding.UTF8.GetBytes(claims))
.Replace('+', '-').Replace('/', '_').Replace("=", "");
var payload = b64header + "." + b64claims;
var message = Encoding.UTF8.GetBytes(payload);
var sig = Convert.ToBase64String(SignData(message))
.Replace('+', '-').Replace('/', '_').Replace("=", "");
return payload + "." + sig;
}
private static byte[] SignData(byte[] message)
{
var privateKeyContent = "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC5Cg7FW0NGwLeD\nrpc0r1Ayta23GxVw0KCA+d/TjSyuZ3lmKiObz9EGJpHSHbX4yrODA6FvYixUrAKm\nUSSMvFLUpYM2xoEgAKnwd6XVgdnjwk7wnIIsEdyjMCbews1orr6Ze+LIPkV2WF4d\nHSAqRqJrERR1Gb9gxKC/WQhMvCotp7zFTqLcUI3eUhR3tIgpLwZFpIxXZjOTwWoB\n6bWxOe39Suft1GYAR0prFcLmXtfw43B+9gVcMLOHBBTLm6QKBgQDiH6vL1plGsIFVWR5M\nESsZdADubhDOtml6r81aKLXJPK9LeHwJOAgTFfZHJD4D4e7KSQfYlbf9tRE7c2PE\ntcj6BVrHdtYRqaXY+Q7BW2mXRb7IJKtVxYPG7DM59oPRqUDs/BSp21nTmSnNC537H0OHlCScpmc7G\ncpj+/jtLIhTN0IwKosaH3mJpQ3AcUI7IooFKgYrC/bwCUQ5xX7CwqaOzTKf3MtX1\nngd7mPWTFkRDxCkCnvfUfcem\n-----END PRIVATE KEY-----";
var rsa = RSA.Create();
var privateKey = privateKeyPem.Replace("-----BEGIN PRIVATE KEY-----", string.Empty).Replace("-----END PRIVATE KEY-----", string.Empty);
privateKey = privateKey.Replace("\n", string.Empty);
privateKey = privateKey.Replace("\r\n", string.Empty);
var privateKeyBytes = Convert.FromBase64String(privateKey);
rsa.ImportPkcs8PrivateKey(privateKeyBytes, out int _);
return rsa.SignData(message, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}
I don't like this manual approach, so i used the .net Cryptography classes to create and sign the JWT Token:
private string GetToken2()
{
// keeping only the payload of the key
var privateKeyPem = "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC5Cg7FW0NGwLeD\nrpc0r1Ayta23GxVw0KCA+d/TjSyuZ3lmKiObz9EGJpHSHbX4yrODA6FvYixUrAKm\nUSSMvFLUpYM2xoEgAKnwd6XVgdnjwk7wnIIsEzlJR5t9tWKLd1VL1133w6jigLv5kDzWQTLAoGBAL0B\n7fS672RBBgOgOtRVhWV7qYvq4aE0bkfRXfxD1GYWnzc6RoyUuvA2glpo9ARzB7ut\nR5LXq5GAwOBIzMhtZWzMZv7ypctiB5DYo/SMiBc7pAxTyE53O9jI5+8g/RB7WlUx\nsZt5bkf42zhsJwZnfV480Hx8GhnCnhGcTVjJbbN5AoGBAInRfNcLpgPtHWiQ5r9W\nANd+XDLpjIUQfh+0NaQeYPG7DM59oPRqUDs/BSp21nTmSnNC537H0OHlCScpmc7G\ncpj+/jtLIhTN0IwKosaH3mJpQ3AcUI7IooFKgYrC/bwCUQ5xX7CwqaOzTKf3MtX1\nngd7mPWTFkRDxCkCnvfUfcem\n-----END PRIVATE KEY-----\n";
var privateKey = privateKeyPem.Replace("-----BEGIN PRIVATE KEY-----", string.Empty).Replace("-----END PRIVATE KEY-----", string.Empty);
privateKey = privateKey.Replace("\n", string.Empty);
privateKey = privateKey.Replace(Environment.NewLine, string.Empty);
var privateKeyRaw = Convert.FromBase64String(privateKey);
// creating the RSA key
using var provider = new RSACryptoServiceProvider();
provider.ImportPkcs8PrivateKey(new ReadOnlySpan<byte>(privateKeyRaw), out _);
var rsaSecurityKey = new RsaSecurityKey(provider);
// Generating the token
var now = DateTime.UtcNow;
var claims = new[] {
new Claim(JwtRegisteredClaimNames.Sub, "10217931234509168826"),
new Claim("email", "myProject-dev.iam.gserviceaccount.com"),
};
var handler = new JwtSecurityTokenHandler();
var token = new JwtSecurityToken
(
"https://accounts.google.com",
"MyAudience",
claims,
now.AddMilliseconds(-30),
now.AddMinutes(60),
new SigningCredentials(rsaSecurityKey, SecurityAlgorithms.RsaSha256)
);
return handler.WriteToken(token);
}
The Google documentation indicates how to sign the JWT:
Sign the UTF-8 representation of the input using SHA256withRSA (also known as RSASSA-PKCS1-V1_5-SIGN with the SHA-256 hash function) with the private key obtained from the Google API Console.
Both the implementation strictly follow the google documentation guidelines, but the generated JWT also fails to validate. I tried several representations of the private key, i.e., replacing the '\n', leaving the '\n', etc, etc, but it always fail.
Both implementations seems correct, but something is missing!
Any ideas on what is missing ?? Thank you in advance.
--------------------- EDIT 1 ---------------------------
To guarantee that the Primary Key data is being correctly handled, and avoid string replacement and encoding, i used the BouncyCastle library which is a lightweight cryptography API, to handle the Primary Key. So i load the JSON KEY file directly, and use BouncyCastle to load the RSA Parameters:
private RSAParameters GetPrivateKeyRSAParameters()
{
var path = "c:\\myproject-key-3433434.json";
using var stream = new FileStream(path, FileMode.Open, FileAccess.Read);
var credentialParameters = NewtonsoftJsonSerializer.Instance.Deserialize<JsonCredentialParameters>(stream);
RSAParameters rsaParams;
using (var tr = new StringReader(credentialParameters.PrivateKey))
{
var pemReader = new PemReader(tr);
if (pemReader.ReadObject() is not AsymmetricKeyParameter key)
{
throw new Exception("Could not read private key");
}
var privateRsaParams = key as RsaPrivateCrtKeyParameters;
rsaParams = DotNetUtilities.ToRSAParameters(privateRsaParams);
}
return rsaParams;
}
This way, instead of relying in handling the Primary Key as text, everything is handled by BouncyCastle.
For code block 1)
var rsa = RSA.Create();
rsa.ImportParameters(GetPrivateKeyRSAParameters());
For code block 2)
var rsaSecurityKey = new RsaSecurityKey(GetPrivateKeyRSAParameters());
So now i have the guarantee that the Primary Key data is being correctly handled, but the end result is the same, the resulting token has always an "Invalid Signature".
--------------------- EDIT 2 ---------------------------
Google has an example on how to do this in JAVA, in this document.
public static String generateJwt(final String saKeyfile, final String saEmail,
final String audience, final int expiryLength)
throws FileNotFoundException, IOException {
Date now = new Date();
Date expTime = new Date(System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(expiryLength));
JWTCreator.Builder token = JWT.create()
.withIssuedAt(now)
.withExpiresAt(expTime)
.withIssuer(saEmail)
.withAudience(audience)
.withSubject(saEmail)
.withClaim("email", saEmail);
FileInputStream stream = new FileInputStream(saKeyfile);
ServiceAccountCredentials cred = ServiceAccountCredentials.fromStream(stream);
RSAPrivateKey key = (RSAPrivateKey) cred.getPrivateKey();
Algorithm algorithm = Algorithm.RSA256(null, key);
return token.sign(algorithm);
}
Replicating the code to .net, i assume it would be as:
private string GetToken5(string path)
{
var now = DateTime.UtcNow;
var claims = new[] { new Claim(JwtRegisteredClaimNames.Sub, "10217931236909168826") };
var handler = new JwtSecurityTokenHandler();
using var stream = new FileStream(path, FileMode.Open, FileAccess.Read);
var serviceAccountCredential = ServiceAccountCredential.FromServiceAccountData(stream);
var token = new JwtSecurityToken
(
"https://accounts.google.com",
"Audience",
claims,
now.AddMilliseconds(-30),
now.AddMinutes(60),
new SigningCredentials(new RsaSecurityKey(serviceAccountCredential.Key), SecurityAlgorithms.RsaSha256)
);
token.Header.Add("kid", "955104a37fa903e232339e83edb29b0c45");
return handler.WriteToken(token);
}
But, this also doesn't work.
There's still something missing ...
Coding wise, the last snippet is a correct way for generating a custom JWT for Google Auth.
The problem is that when a Service Account is created, it has a specific PUBLIC KEY which is used to verify the Token.
When creating the token with the Issuer as "https://accounts.google.com", when verifying the token, another public key was used, thus the validation failed.
The solution was to implement our own .well-known/openid-configuration Endpoint, and matching the Token claims with the information provided by this endpoint.
I try to retrieve a record from Dynamics 365 Sales. I created an app registration in Azure and I can get tokens based on this app.
Also, I can call the HTTP client. But I couldn't figure out how to read the result of the HTTP call.
Microsoft published only WhoAmIRequest sample, but I couldn't find a sample of other entities.
Here is my sample code. I try to read body object.
try
{
string serviceUrl = "https://****.crm4.dynamics.com/";
string clientId = "******";
string clientSecret = "*******";
string tenantId = "*******";
A***.Library.Utility.MSCRM mscrm = new Library.Utility.MSCRM(serviceUrl, clientId, clientSecret, tenantId);
var token = await mscrm.GetTokenAsync();
Console.WriteLine(token);
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(serviceUrl);
client.Timeout = new TimeSpan(0, 2, 0); //2 minutes
client.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
client.DefaultRequestHeaders.Add("OData-Version", "4.0");
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "/api/data/v9.0/accounts");
// Set the access token
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
HttpResponseMessage response = client.SendAsync(request).Result;
if (response.IsSuccessStatusCode)
{
// Get the response content and parse it.
var responseStr = response.Content.ReadAsStringAsync();
JObject body = JObject.Parse(response.Content.ReadAsStringAsync().Result);
}
}
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
Here is the result of body object.
You can use either of these syntax to read values. Read more
JObject body = JObject.Parse(response.Content.ReadAsStringAsync().Result);
// Can use either indexer or GetValue method (or a mix of two)
body.GetValue("obs_detailerconfigid");
body["obs_detailerconfigid"];
I am trying to do this article for google cloud build
https://cloud.google.com/endpoints/docs/openapi/service-account-authentication
I am guessing to use the service account email I generated the key from in that example AND for Audient, I put "" (which is probably the reason it's not working?). I have no idea and can't find what in the world to put for audience.
In addition to code below, I tried setting audience to 'https://cloudbuild.googleapis.com' which also did not work
My code is the following...
public class GenToken {
public static void main(String[] args) throws IOException {
Duration d = Duration.ofDays(365);
String tok = generateJwt("/Users/dean/workspace/order/java/googleBuild/orderly-gcp-key.json",
"mycloudbuilder#order-gcp.iam.gserviceaccount.com", "", d.toSeconds());
System.out.println("tok="+tok);
URL url = new URL("https://cloudbuild.googleapis.com/v1/projects/order-gcp/builds");
makeJwtRequest(tok, "GET", url);
}
public static String generateJwt(final String saKeyfile, final String saEmail,
final String audience, final long expiryLength)
throws FileNotFoundException, IOException {
Date now = new Date();
Date expTime = new Date(System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(expiryLength));
// Build the JWT payload
JWTCreator.Builder token = JWT.create()
.withIssuedAt(now)
// Expires after 'expiraryLength' seconds
.withExpiresAt(expTime)
// Must match 'issuer' in the security configuration in your
// swagger spec (e.g. service account email)
.withIssuer(saEmail)
// Must be either your Endpoints service name, or match the value
// specified as the 'x-google-audience' in the OpenAPI document
.withAudience(audience)
// Subject and email should match the service account's email
.withSubject(saEmail)
.withClaim("email", saEmail);
// Sign the JWT with a service account
FileInputStream stream = new FileInputStream(saKeyfile);
ServiceAccountCredentials cred = ServiceAccountCredentials.fromStream(stream);
RSAPrivateKey key = (RSAPrivateKey) cred.getPrivateKey();
Algorithm algorithm = Algorithm.RSA256(null, key);
return token.sign(algorithm);
}
/**
* Makes an authorized request to the endpoint.
*/
public static String makeJwtRequest(final String signedJwt, String method, final URL url)
throws IOException, ProtocolException {
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod(method);
con.setRequestProperty("Content-Type", "application/json");
con.setRequestProperty("Authorization", "Bearer " + signedJwt);
InputStreamReader reader = new InputStreamReader(con.getInputStream());
BufferedReader buffReader = new BufferedReader(reader);
String line;
StringBuilder result = new StringBuilder();
while ((line = buffReader.readLine()) != null) {
result.append(line);
}
buffReader.close();
return result.toString();
}
}
The orderly-gcp-key.json has these attributes in it
{
"type": "service_account",
"project_id": "myproj",
"private_key_id": "xxxxxxxx",
"private_key": "-----BEGIN PRIVATE KEY-----\nasdfsd\n-----END PRIVATE KEY-----\n",
"client_email": "build-ci-mine#myproj.iam.gserviceaccount.com",
"client_id": "1167333552",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/build-ci-mine%40myproj.iam.gserviceaccount.com"
}
oops, my edit didn't get posted :(. Here is the error
Exception in thread "main" java.io.IOException: Server returned HTTP response code: 401 for URL: https://cloudbuild.googleapis.com/v1/projects/orderly-gcp/builds
at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1919)
at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1515)
at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:250)
at com.orderlyhealth.auth.websecure.GenToken.makeJwtRequest(GenToken.java:71)
at com.orderlyhealth.auth.websecure.GenToken.main(GenToken.java:26)
I hope that I better understood!!
When you try to reach a Google API, you have to use an access token. I have 2 code snippets for you.
Use Google Http client
GoogleCredentials credentials = GoogleCredentials.getApplicationDefault();
HttpRequestFactory factory = new NetHttpTransport().createRequestFactory(new HttpCredentialsAdapter(credentials));
HttpRequest request = factory.buildGetRequest(new GenericUrl("https://cloudbuild.googleapis.com/v1/projects/gbl-imt-homerider-basguillaueb/builds"));
HttpResponse httpResponse = request.execute();
System.out.println(CharStreams.toString(new InputStreamReader(httpResponse.getContent(), Charsets.UTF_8)));
Use pure java connection
GoogleCredentials credentials = GoogleCredentials.getApplicationDefault();
HttpURLConnection con = (HttpURLConnection) new URL("https://cloudbuild.googleapis.com/v1/projects/gbl-imt-homerider-basguillaueb/builds").openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("Content-Type", "application/json");
con.setRequestProperty("Authorization", "Bearer " + credentials.refreshAccessToken().getTokenValue());
InputStreamReader reader = new InputStreamReader(con.getInputStream());
BufferedReader buffReader = new BufferedReader(reader);
String line;
StringBuilder result = new StringBuilder();
while ((line = buffReader.readLine()) != null) {
result.append(line);
}
buffReader.close();
System.out.println(result.toString());
You can rely on the platform environment. In local, perform a gcloud auth application-default login to set your credential as default default credential. On GCP, the component identity (the default service account or the service account that you define when you create the component), is used thanks to the method GoogleCredentials.getApplicationDefault();
Your dependency management need this (here in maven)
<dependency>
<groupId>com.google.auth</groupId>
<artifactId>google-auth-library-oauth2-http</artifactId>
<version>0.20.0</version>
</dependency>
Does this solve your issue?
I have a website which exposes an ODatas $metadata but to do anything further requires the request to be authenticated (using a cookie).
I want to access this from a console app, not a browser.
I am using Microsofts Odata V4 client code generator.
1) Create a wrapper around the provided Container created by the OData client code generator.
2) Log in and get the cookie you need for authentication
3) Add a hook to the request builder, so you can apply cookies at request time. For my app, I specifically needed the cookie with the name .AspNet.ApplicationCookie
Here is a full working example. You can instantiate this container with the user and password needed as defined at the bottom. This MUST match whatever the controller at the Login API is expecting.
using Nito.AsyncEx;
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace MyAppOdataOdataService.Default
{
public class MyAppOdataContainer : Container
{
public Cookie[] _MyAppOdataAuthcookie;
public string cookieAuthName = ".AspNet.ApplicationCookie";
private string baseurl = "https://TheAppwWebsite.co.jp/";
public MyAppOdataContainer(MyAppOdataLoginInfo logininfo ) :
base(new Uri("https://TheAppwWebsite.co.jp/odata/"))
{
// init authorization
_MyAppOdataAuthcookie = AsyncContext.Run(() => AuthenticateUser(logininfo));
if (_MyAppOdataAuthcookie == null) throw new UnauthorizedAccessException();
this.BuildingRequest += AddCookie;
}
private void AddCookie(object sender, Microsoft.OData.Client.BuildingRequestEventArgs e)
{
e.Headers.Add("Cookie", cookieAuthName+"=" + _MyAppOdataAuthcookie.First(c=>c.Name == cookieAuthName).Value);
}
private async Task<Cookie[]> AuthenticateUser(MyAppOdataLoginInfo logininfo)
{
CookieContainer cookies = new CookieContainer();
HttpClientHandler handler = new HttpClientHandler();
handler.CookieContainer = cookies;
HttpClient client = new HttpClient(handler);
client.BaseAddress = new Uri(baseurl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
Uri uri = new Uri(baseurl + "/Login/Login");
HttpResponseMessage response = await client.PostAsJsonAsync(uri, logininfo);
response.EnsureSuccessStatusCode();
// Return the URI of the created resource.
return cookies.GetCookies(uri).Cast<Cookie>().ToArray();
}
}
public class MyAppOdataLoginInfo
{
public string Username { get; set; }
public string Password { get; set; }
}
}
Thanks:
How to apply the cookie:
Creating the client code:
CookieContainer explaination:
Post operation idea here - for authorizing - having to use PostAsJsonAsync
Since it' apparently not possible to authenticate with LDAP on my BlackBerry App, I'm trying to use a kind of workaround. Instead of authenticate directly on the LDAP Server, I want to use a Web Service in between. So it looks like this
App --calls--> Web Service --calls--> LDAP Server
So the Web Service should take the username and password given from the Application and send it to the LDAP Server. If its possible to sign in, the Web Service gets a TRUE as response and forward it to the App.
That's how it should work. But at the moment, when I call the Web Service from the App, I get following error:
SoapFault - faultcode: 'S:Server' faultstring:
'java.lang.NullPointerException' faultactor: 'null' detail:
org.kxml2.kdom.Node#21e05a11
Seems like a Server problem but I don't know where :(
Well, that's the Web Service I'm using:
import javax.ejb.Stateless;
import javax.jws.WebService;
import com.novell.ldap.LDAPConnection;
import com.novell.ldap.LDAPException;
#Stateless
#WebService()
public class ldapServiceBean implements ldapService {
#Override
public String error() {
// TODO Auto-generated method stub
return null;
}
#Override
public boolean ldapLogin(String username, String password) {
int ldapPort = LDAPConnection.DEFAULT_PORT;
int ldapVersion = LDAPConnection.LDAP_V3;
String ldapHost = "dc1.somehost ";
String loginDN =
"CN="+username+",OU=employee,OU=user,DC=somehost";
byte[] passwordBytes = password.getBytes();
LDAPConnection lc = new LDAPConnection();
try {
// connect to the server
lc.connect( ldapHost, ldapPort );
// authenticate to the server
lc.bind( ldapVersion, loginDN, passwordBytes );
System.out.println("Bind successful");
return true;
}
catch( LDAPException e ) {
if ( e.getResultCode() == LDAPException.NO_SUCH_OBJECT ) {
System.err.println( "Error: No such entry" );
} else if ( e.getResultCode() ==
LDAPException.NO_SUCH_ATTRIBUTE ) {
System.err.println( "Error: No such attribute" );
} else {
System.err.println( "Error: " + e.toString() );
}
}
return false;
}
And that's the method calling the Web Service
private static final String SOAP_ACTION = "";
private static final String METHOD_NAME = "ldapLogin";
private static final String NAMESPACE = "http://ldapproxy.somehost/";
private static final String URL = "http://myIP:8080/LDAPProxy/ldapServiceBeanService";
...
public boolean login(String username, String password) {
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
//SoapObject
request.addProperty("username", username);
request.addProperty("password", password);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
//envelope.dotNet = true;
//envelope.bodyOut = request;
envelope.setOutputSoapObject(request);
HttpTransport httpTransport = new HttpTransport(URL);
try
{
httpTransport.call(SOAP_ACTION, envelope);
System.out.println("request: " + httpTransport.requestDump);
resultsRequestSOAP = (SoapObject) envelope.getResponse();
return true;
}catch(SoapFault sF){
String error = sF.toString();
Dialog.alert(error);
}
catch (Exception aE)
{
Dialog.alert("Connection failed");
aE.printStackTrace ();
}
return false;
}
What I found out so far:
It seems that the webservice don't receives the username and password property. As I print them I get:
`CN=null, OU=employee, OU=...`
Like I've read at this post Web service recieves null parameters from application using ksoap method it seems ksoap have a problem with colons. I changed my NAMESPACE but without any success. Maybe I need to change my URL too. But how would I do this while I still need to use localhost ?
As always when doing LDAP bind testing this way, recall that the standard requires that a bind of a username, no password, is a successful Anonymous bind, so therefore you MUST validate for this case (empty password) on login attempts.