I want my Domino Servlet to get an authenticated user session - session

It seems a like a pretty fundamental question, in a running Servlet hosted on Domino I want to access Domino resources that I have wisely protected using the the very fine security of IBM Notes and Domino.
I want the Servlet to be able to read and write data to Domino whilst keeping that data from the client that called the Servlet (or xAgent) and preventing the client from writing directly.
I'd be happy to be able to get a session that represented the signer of the application. I can get a session for a registered user by calling the Servlet using ?open&login and signing in. That's not practical.
I've looked here: How can you use SessionAsSigner in a Java Bean called from an XPage? where Mark Leusink (https://stackoverflow.com/users/1177870/mark-leusink) implies the use of ExtLib's getCurrentSessionAsSigner() could be used. I've tried it, having signed the whole application with a single user id and it doesn't return a session. The answer seems to lie in the Servlet's inability to get a FacesContext object.
This feels like the answer should be obvious but it isn't to me. Any ideas?

FacesContext is JSF stuff and can be used from XAgent (=XPage).
In a servlet you can do this:
Session session = NotesFactory.createSession(null, "user", "password");
Server ID usually has no password and doing this will use the server ID:
Session session = NotesFactory.createSession();

Check the source of the WebDav project on OpenNTF. It has all the code you need

There have been lots of good answers to the original question. Thanks very much.
The solution I propose to use is to port the code I have to OSGi plugins. It appears that java code/Servlets within the NSF context are subject to security controls that are relaxed when the same code runs within the OSGi context. The code:
try {
NotesThread.sinitThread();
Session s = NotesFactory.createSession("","<my username>","<my password>");
.....
session = null;
} catch (Exception e) {
} finally {
NotesThread.stermThread();
}
Runs fine in the OSGI context, but within in an NSF produc

com.ibm.domino.osgi.core.context.ContextInfo.getUserSession()

Jason - I assume you basically want the same functionality you would get running a Web Query Save agent if you didn't select run as Web User selected, in other words as the signer of the code.
You could try setting up a internet site rule to allow basic authentication for the specific application path you wanted to use - might be worth using a subdomain for this.
Then within the Servlet call this URL, whilst setting the Basic authorization parameters (username & password).
Something like this.
URL url = new URL(URL_TO_CALL);
String authStr = "USERNAME:PASSWORD";
String authEncoded = Base64.encodeBytes(authStr.getBytes());
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setDoOutput(true);
connection.setRequestProperty("Authorization", "Basic " + authEncoded);
InputStream is = connection.getInputStream();

Related

Calling internal (Endpoint) function in WebAPI

I am using Hangfire to execute recurring jobs in my web API and I use System.Web.HttpContext.Current.Server.MapPath in the "RoutineMethod" function.
But the problem is it throws object null exception.
I searched the problem and found that recurring jobs don't use http threads, they use background threads.
Now to resolve this problem I need to call my internal (endpoint) using httpclient.
But to do that I need to give URL of the Web API (to generate URI). So is there any other way to call internal function using httpclient.
My current code:
public static async Task<IHttpActionResult> RoutineTask()
{
//It was like this before.
//await new DemoController().RoutineMethod();
//await new DemoController().RoutineMethod2();
//I am planning to do this.
using (var client = new HttpClient())
{
//But I need to give URI which I don't think is a good idea.
var uri = new Uri("http://localhost/DemoApp/api/DemoController/RoutineMethod");
await client.GetAsync(uri);
}
return new DemoController().Ok();
}
The short answer is no. The HttpClient, as its name implies, requires an http connection.
There are no smell issues with storing service connection information in a configuration file.
However, to expand on Nkosi's comment, it appears that since your code can create an instance of DemoController, that it must have a reference to that controller's project or even be in the same project. I would extract the interesting code into a library or service that all areas needing the information can reference.

How to speed up the restlet client to get response?

I use restlet client to send rest request to the server.
public class RestHandler {
protected ClientResource resource = null;
protected Client client = null;
public void connect(final String address,
final Protocol protocol){
final Context context = new Context();
if (client == null) {
logger.info("Create Client.");
client = new Client(context, protocol);
}
resource = new ClientResource(context, new Reference(protocol, address));
resource.setNext(client);
resource.setEntityBuffering(true);
}
}
In its child class, use resource.get()/post/put/delete to send rest request.
I found the response come back so slow at the first time(5-10s).
And then it go faster in the next few requests.
But after waiting about 10min I send the request again, it become slow again.
Is there any way to make the response come back faster?
You can try to use another client connector. It can be the cause of your problem, especially if you use the default one. Notice that the default one should be used for development only.
This page gives you all the available client connectors: http://restlet.com/technical-resources/restlet-framework/guide/2.3/core/base/connectors.
Regarding client connectors, you can configure properties to tune them. To use a client connector, simply put the corresponding Restlet extension within your classpath. Perhaps can you make a try with the extension org.restlet.ext.httpclient.
This answer could help you regarding connector configuration and properties: Restlet HTTP Connection Pool.
Hope it helps you,
Thierry

Google Drive SDK 1.8.1 RedirectURL

Is there any way to provide RedirectURL then using GoogleWebAuthorizationBroker?
Here is the sample code in C#:
Task<UserCredential> credential = GoogleWebAuthorizationBroker.AuthorizeAsync(secrets, scopes, GoogleDataStore.User, cancellationToken, dataStore);
Or we have to use different approach?
I have an "installed application" that runs on a user's desktop, not a website. By default, when I create an "installed application" project in the API console, the redirect URI seems to be set to local host by default.
What ends up happening is that after the authentication sequence the user gets redirected to localhost and receives a browser error. I would like to prevent this from happening by providing my own redirect URI: urn:ietf:wg:oauth:2.0:oob:auto
This seems to be possible using Python version of the Google Client API, but I find it difficult to find any reference to this with .NET.
Take a look in the implementation of PromptCodeReceiver, as you can see it contains the redirect uri.
You can implement your own ICodeReceiver with your prefer redirect uri, and call it from a WebBroker which should be similar to GoogleWebAuthorizationBroker.
I think it would be great to understand why can't you just use PrompotCodeReceiver or LocalServerCodeReceiver.
And be aware that we just released a new library last week, so you should update it to 1.9.0.
UPDATE (more details, Nov 25th 2014):
You can create your own ICodeReceiver. You will have to do the following:
* The code was never tested... sorry.
public class MyNewCodeReceiver : ICodeReceiver
{
public string RedirectUri
{
get { return YOU_REDIRECT_URI; }
}
public Task<AuthorizationCodeResponseUrl> ReceiveCodeAsync(
AuthorizationCodeRequestUrl url,
CancellationToken taskCancellationToken)
{
// YOUR CODE HERE FOR RECEIVING CODE FROM THE URL.
// TAKE A LOOK AT THE FOLLOWING:
// PromptCodeReceiver AND LocalServerCodeReceiver
// FOR EXAMPLES.
}
}
PromptCodeReceiver
and LocalServerCodeReceiver.
Then you will have to do the following
(instead of using the GoogleWebAuthorizationBroker.AuthorizeAsync method):
var initializer = new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = secrets,
Scopes = scopes,
DataStore = new FileDataStore("Google.Apis.Auth");
};
await new AuthorizationCodeInstalledApp(
new GoogleAuthorizationCodeFlow(initializer),
new MyNewCodeReceiver())
.AuthorizeAsync(user, taskCancellationToken);
In addition:
I'll be happy to understand further why you need to set a different redirect uri, so we will be able to improve the library accordingly.
When I create an installed application the current PromptCodeReceiver and LocalServerCodeReceiver work for me, so I'm not sure what's the problem with your code.

how to pass a target database on H2 database console

I'm using H2 database console as a servlet in my own web application that provides a front end of many databases.
How to skip or help a login step at H2 database console by passing some parameters in my own code?
(I have many databases, so I won't use "saved settings" first.)
imaginary: http://myapp/h2console/login.do?user=scott&password=tiger&url=jdbc:thin:......
Because of the somewhat special session handling of the console, this is not possible just using an fixed URL. (The session handling allows to open multiple connections within multiple tabs from one browser, which is not possible when using cookies.)
However, what you can do is create a URL in the same way as Server.startWebServer(Connection conn) does:
// the server is already running in your case,
// so most likely you don't need the following lines:
WebServer webServer = new WebServer();
Server web = new Server(webServer, new String[] { "-webPort", "0" });
web.start();
Server server = new Server();
server.web = web;
webServer.setShutdownHandler(server);
// this will create a new session and return the URL for it:
String url = webServer.addSession(conn);

Getting "Object is read only" error when setting ClientCredentials in WCF

I have a proxy object generated by Visual Studio (client side) named ServerClient. I am attempting to set ClientCredentials.UserName.UserName/Password before opening up a new connection using this code:
InstanceContext context = new InstanceContext(this);
m_client = new ServerClient(context);
m_client.ClientCredentials.UserName.UserName = "Sample";
As soon as the code hits the UserName line it fails with an "Object is read-only" error. I know this can happen if the connection is already open or faulted, but at this point I haven't called context.Open() yet.
I have configured the Bindings (which uses netTcpBinding) to use Message as it's security mode, and MessageClientCredentialType is set to UserName.
Any ideas?
I noticed that after creating an instance of the proxy class for the service, I can set the Username and Password once without errors and do a successful call to my webservice. When I then try to set the Username and Password again on the existing instance (unnecessary of course) I get the 'Object is Read-Only' error you mentioned. Setting the values once per instance lifetime worked for me.
It appears that you can only access these properties pretty early in the instanciation cycle. If I override the constructor in the proxy class (ServerClient), I'm able to set these properties:
base.ClientCredentials.UserName.UserName = "Sample";
I'm beginning to appreciate the people who suggest not using the automatically built proxies provided by VS.
here is the solution:
using SysSvcmod = System.ServiceModel.Description;
SysSvcmod.ClientCredentials clientCredentials = new SysSvcmod.ClientCredentials();
clientCredentials.UserName.UserName = "user_name";
clientCredentials.UserName.Password = "pass_word";
m_client.ChannelFactory.Endpoint.Behaviors.RemoveAt(1);
m_client.ChannelFactory.Endpoint.Behaviors.Add(clientCredentials);
I have similar code that's passing UserName fine:
FooServiceClient client = new FooServiceClient("BasicHttpBinding_IFooService");
client.ClientCredentials.UserName.UserName = "user";
client.ClientCredentials.UserName.Password = "password";
Try creating the proxy with binding name in app.config.
The correct syntax is:
// Remove the ClientCredentials behavior.
client.ChannelFactory.Endpoint.Behaviors.Remove<ClientCredentials>();
// Add a custom client credentials instance to the behaviors collection.
client.ChannelFactory.Endpoint.Behaviors.Add(new MyClientCredentials());
http://msdn.microsoft.com/en-us/library/ms730868.aspx
It worked for me.
I was facing same problem, my code started working when I changed my code i.e. assigning values to Client credential immediately after initializing Client object.
here is the solution ,
ProductClient Manager = new ProductClient();
Manager.ClientCredentials.UserName.UserName = txtUserName.Text;
Manager.ClientCredentials.UserName.Password = txtPassword.Text;
This will not happen if the service reference is added through -> Add service reference ->Advanced->Add Web Reference-> Url/wsdl (local disk file).
I was facing this issue where I was trying to create a generic method to create a clients for different end points.
Here how I achieved this.
public static T CreateClient<T>(string url) where T : class
{
EndpointAddress endPoint = new EndpointAddress(url);
CustomBinding binding = CreateCustomBinding();
T client = (T)Activator.CreateInstance(typeof(T), new object[] { binding, endPoint });
SetClientCredentials(client);
return client;
}
public static void SetClientCredentials(dynamic obj)
{
obj.ChannelFactory.Endpoint.Behaviors.Remove<ClientCredentials>();
obj.ChannelFactory.Endpoint.Behaviors.Add(new CustomCredentials());
obj.ClientCredentials.UserName.UserName = "UserId";
obj.ClientCredentials.UserName.Password = "Password";
}
I think your problem might be related to the use of the InstanceContext. I thought that was only needed for duplex communication channels from the server side.
I admit I'm not sure about this, but I think in this case you are telling the client to use an existing instance context so it thinks there is already a running service and will not allow changes.
What is driving the use of InstanceContext?
If using a duplex client, when you instantiate it the DuplexChannelFactory within the DuplexClientBase that your client is derived from is initialized with existing credentials so it can open the callback channel, which is why the credentials would be read only.
I second Mike's question and also ask why are you using NetTcpBinding if you are not going to use its inherent transport level security? Perhaps an HTTP based binding would be a better fit? That would allow you to use certificate based security which I believe can be modified after instantiation (http://msdn.microsoft.com/en-us/library/ms576164.aspx).
A shot in the dark but does netTcpBinding allow username and password validation? Try using application layer (SOAP) security using a http binding
or you could just simply check the Credentials
if (client.ClientCredentials.ClientCertificate.Certificate == null || string.IsNullOrEmpty(client.ClientCredentials.ClientCertificate.Certificate.Thumbprint))
{
client.ClientCredentials.ClientCertificate.SetCertificate(
StoreLocation.LocalMachine,
StoreName.My,
X509FindType.FindByThumbprint, ConfigurationManager.AppSettings.Get("CertificateThumbprint"));
}
In .NET 4.6 I couldn't remove the credentials using Fabienne's answer. Kept getting Compiler Error CS0308 in the Remove method. What worked for me was this:
Type endpointBehaviorType = serviceClient.ClientCredentials.GetType();
serviceClient.Endpoint.EndpointBehaviors.Remove(endpointBehaviorType);
ClientCredentials clientCredentials = new ClientCredentials();
clientCredentials.UserName.UserName = userName;
clientCredentials.UserName.Password = password;
serviceClient.Endpoint.EndpointBehaviors.Add(clientCredentials);

Resources