I have the beginnings of a standard Silverlight/ RIA/ EF application that is just working straight away as expected.
I wanted to restrict my entire DomainService to only authenticated users, as the application will eventually live on the public internet, and all data access needs to be user authenticated.
The problem I have, is that I cannot use the auto-generated DomainContext class in my Silverlight app unless I wrap all of its Load methods inside a custom class that verifies the authentication status of the user before attempting to retrieve data - which seems like a long and tedious coding task.
Surely there must be a simple solution that Ive missed ?
This stuff was easy in ASP.NET because the moment you lost (or never had) authentication you were redirected to a login page (as configured in web.config).
Im really suprised theres no similar mechanism in Silverlight, as it seems to be to be a standard business application requirement.
Requiring authentication in your DomainService is easy. Just add a [RequiresAuthentication] or [RequiresRole] attribute to either the class (applies to all operations) or operation you want to authorize. You might find these links helpful.
How to: Enable Authentication in RIA Services
RequiresAuthenticationAttribute
I am not 100% sire if this is the answer you want and if it's a good practice to do it like this but you could implement a message inspector that inspects whether the user is authenticated like this:
public class ClientCustomHeadersDispatchMessageInspector : IDispatchMessageInspector
{
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
if (!HttpContext.Current.User.Identity.IsAuthenticated) {
throw new SecurityException("User not authenticated");
}
return null;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{
}
}
Related
I assume I can build an additional API that registers users/apps/containers.
But is there a simpler way to accept multiple clients dynamically ?
That is for example, if my IDP is in the UK, and i would like to allow a predefined containers to "add themselves" to the client list of my IDP.
I achieved a simple "User -> Client -> IDP" authentication but would like to automate the process.
Thank you fellow coders.
In short, yes - but you'd have to create the mechanism to do so yourself.
If using a database to back your client storage (rather than using the default static/config file based in-memory store) then you're free to implement that any way you like.
In our solution we have an API that allows for this as well as a more limited self-serve UI capability.
There is an OpenID Connect spec for this that may provide some inspiration: https://openid.net/specs/openid-connect-registration-1_0.html
You can implement you own client store using IClientStore interface.
Something like
internal class MyCustomClientStore : IClientStore
{
public Task<Client> FindClientByIdAsync(string clientId)
{
throw new System.NotImplementedException();
}
}
You can store client data anywhere you want, interface is pretty simple.
This implementation can be registered using DI with
services
.AddIdentityServer()...
.AddClientStore<MyCustomClientStore>()
I'm new to Google Cloud Endpoints and I am currently looking for an alternate way to receive the User method parameter.
In the documentation on Authenticating Users, the only way of receiving information about the user that is shown is to receive an instance com.google.api.server.spi.auth.common.User as a method parameter.
There appears to be no annotation I can use to request this principle elsewhere other than directly on the endpoint method. This can obviously be made to work, but I am very interested in the following scenario:
/*
* in an injection provider
*/
CustomUserClass getUser(#EndpointsUser User user) throws UnauthorizedException{
if(user == null) throw new UnauthorizedException("If we're requesting the user be injected, we should reject unauthenticated requests");
//datastore code to lookup and return my representation of a user
}
/*
* in the endpoint class
*/
#Inject
CustomUserClass userProfile;
//endpoint methods here
Does anyone know how to do the above? I realize I could simply move this logic into my endpoint class, but this is a case of cross-cutting concerns and is not only bad programming, but less easily tested.
Yes, I know I can role my own solution (pun intended), but cloud endpoints is supposed to make this kind of thing easy, isn't it?
This is currently not possible, as Guice use cases weren't common when the frameworks were written. You can file a feature request.
I have 4 WCF services that I have developed.
Each service is responsible for something else.
Each service has a UserNamePasswordValidator, so clients need to supply credentials when connecting.
I would now like to develop my WPF client application, in an MVVM architecture.
I would like for the WPF application to load with a 'Login' screen,
where the user will input a username and password,
and then this will be passed on to the 4 clients for the 4 WCF services (all use the same username and password).
What is the best approach to doing this ?
Where are the clients located ? in the 'Model' part ? which view's model ?
The WCF Service needs to be consumed by multiple views, so I don't think I can put any of the WCF service clients in a specific Model class...
To do this, we have created a ServiceFactory class that connects to a service given its endpoint and an appropriate IClientChannel-derived interface. This assumes that you are using the WCF services directly, e.g. not via the VS-generated proxies, since you need to set the username and password values on each client channel creation.
The client channel interfaces are in an external "service library" along with the service factory, so they can be shared with the WCF service implementations and the clients. We store the credentials in a static state dictionary (though you also put it, for example, into the main resource dictionary) with the password being saved in a SecuredString for a tiny bit of extra security.
I've described the basic process for creating such a service factory on by blog:
http://blog.kutulu.org/2012/03/proxy-free-wcf-ditching-proxy.html
In our case, we perform a setup routine in App.xaml.cs that prompts for credentials and makes an attempt to call one of our services, looping until we get a successful login. That code is much more complex, but it's basically:
while (true)
{
var factory = new ChannelFactory<ITestChannel>(new WSHttpBinding("SecuredBinding"));
ITestChannel client = null;
try
{
factory.Credentials.UserName.UserName = logOnModel.UserName;
factory.Credentials.UserName.Password = logOnModel.Password;
var address = Settings.Default.TestServiceUrlBase));
client = factory.CreateChannel(address);
break;
}
// Catch various exceptions here.
}
The trick here is that, if your login or password is wrong and your UsernamePasswordValidator fails your login, you'll get a MessageSecurityException which will fault your channel, so you'll need to close it and open a new one. But you cannot change the credentials on a ChannelFactory once you've opened the first channel, so you need to dispose and re-create a new factory and new client channel every time.
We also check for CommunicationException and ArgumentException here in case the URL is wrong.
Once that's done, you can use similar code in your service factory class to construct a client, given its channel interface, and set up the credentials for each call. (We actually cache the service factories for each distinct interface because we create and destroy channel frequently, but that's up to you.)
I'm attempting to consume a SOAP service in a Silverlight 5 application and I'm completely lost. This is my first Silverlight app and only my second time using web services in a .NET application.
In a separate .NET application, the only way I was able to get it to work was by adding the WSDL as a Web Reference; the application would not build when I added it as a Service Reference. In talking to the WSDL provider, I discovered that the WSDL was compiled using the .NET 2.0 framework...hence the need to add it as a Web Reference.
From the research I've done thus far, I see that Silverlight doesn't support adding a Web Reference. So I tried adding it to the hosting ASP.NET application as a Web Reference then started the server.
Back in my Silverlight app, I selected the option to add a Service Reference and pointed to the WSDL file now at http://localhost:55265/Web%20References/THINKWebService/SLWebSvc_734_Upgrade.wsdl. Visual Studio seemed to pick it up just fine and generate the proxies.
Here's where I start to get stuck. If my research is correct, a WCF reference was created and should be used in that manner. I've never used WCF so I did some reading on how to send/receive requests and this is the best code I've come up with, based on examples in the MSDN library (I inserted it into a button click event so I would know exactly when the code was executing):
private void Button1Click(object sender, RoutedEventArgs e)
{
var client = new ThinkSoapClient();
var userLoginData = new user_login_data {login = "foo", password = "bar"};
var customerIdentifier = new customer_identifier {customer_id = 6677070};
// the debugger halts on this next line and
// references the "dsn"...it's the 4th argument
client.CustomerLoginInfoSelectAsync(userLoginData, customerIdentifier, "", "myDSN");
// I'm not sure if this next line is even needed
client.CustomerLoginInfoSelectCompleted += CustomerLoginInfoSelectCallback;
MessageBox.Show(string.Format("CustomerLoginInfoSelectAsync({0},{1})", userLoginData, customerIdentifier));
}
// here's the callback method
static void CustomerLoginInfoSelectCallback(object sender, CustomerLoginInfoSelectCompletedEventArgs e)
{
MessageBox.Show(string.Format("CustomerLoginInfoSelect Result: {0}", e.Result));
}
As I mentioned in the code above, the debugger halts when executing the client.CustomerLoginInfoSelectAsync method. Here's the error message: XmlSerializer attribute System.Xml.Serialization.XmlAttributeAttribute is not valid in dsn. Only XmlElement, XmlArray, XmlArrayItem and XmlAnyElement attributes are supported when IsWrapped is true.
From the research I've done, I think this error is being caused because the the SOAP action element contains an attribute dsn (not sure, though, if I would be getting this error if the sub-elements also had attributes).
I did a find/replace for IsWrapped=true to IsWrapped=false in Reference.cs but I got the same error but the last word was false instead of true.
I'm not sure if I'm making any sense as to what I'm after, so here's what the generated XML should look like in case it helps:
...
<customer_login_info_select_request dsn="myDSN">
<user_login_data>
<login>foo</login>
<password>bar</password>
</user_login_data>
<customer_identifier>
<customer_id>6677070</customer_id>
</customer_identifier>
<login/> <!--corresponds to the empty string in the call to CustomerLoginInfoSelectAsync-->
</customer_login_info_select_request>
...
So at this point, I'm completely lost. Any insights would be greatly appreciated. If there's any other info I can provide, please let me know.
While possible the normal solution would be to assume it is "just another data source" and use the Web reference on your Server side instead to provide data (and to provide insulation against future changes).
Silverlight App <=> Silverlight Web Services <= External/Legacy Web Service
Keep your Silverlight app slim and let the server do any heavy lifting for you.
I was browsing through the code of Vosao CMS, an open source CMS hosted on Google App Engine (which I think is an awesome idea), and I stumbled upon the following code inside the CurrentUser class:
/**
* Current user session value cache class. Due to GAE single-threaded nature
* we can cache currently logged in user in static property. Which we set in
* authentication filter.
*/
public class CurrentUser {
private static UserEntity user;
public static UserEntity getInstance2() {
return user;
}
public static void setInstance2(UserEntity aUser) {
user = aUser;
}
}
I've never used GAE, but this sounds really weird to me.
Is GAE really "single threaded"? Is it safe to store request-scoped data inside a static field when using GAE?
Does this mean that, for each JVM instance, only one HTTP request will be executed at a time, while all the other requests are waiting?
Is this a common GAE idiom? If not, what would be the best GAE idiom to store such an UserEntity for the duration of a request? Shouldn't one use a ThreadLocal here, like they do in Spring Security? Or some kind of scoped bean (managed by the Dependency Injection container)?
Is GAE really "single threaded"? Is it safe to store request-scoped data inside a static field when using GAE?
It used to be that way (until 1.4.3) and it still is by default.
Now, you can specify that your app is threadsafe, and then you will receive concurrent requests to the same JVM/servlet.
Does this mean that, for each JVM instance, only one HTTP request will be executed at a time, while all the other requests are waiting?
For other request, you would probably get another JVM. But that is outside of your control. They can also just wait.
Currently, the Java and Python runtimes on App Engine are both single threaded; you're correct that this means only one HTTP request will be executed per JVM, but multiple JVMs will be started simultaneously to handle multiple incoming requests.
This could change at any time in the future, however - the Java Servlet spec permits multi-threading. As a result, you should definitely use a ThreadLocal.