I'm currently trying out Silverlight with RIA Services. I'm implementing a simple login form. I'm also using the provided Authentication Domain Service template which generates the following file:
[EnableClientAccess]
public class AuthenticationDomainService : AuthenticationBase<User>
{
// To enable Forms/Windows Authentication for the Web Application,
// edit the appropriate section of web.config file.
}
public class User : UserBase
{
// NOTE: Profile properties can be added here
// To enable profiles, edit the appropriate section of web.config file.
// public string MyProfileProperty { get; set; }
public int DefaultRows { get; set; }
}
Now I can login/logout without problem in my application. In the Silverlight app, after logging in, the line:
WebContext.Current.User.IsAuthenticated;
return true.
However, I need to persist this across sessions (i.e. when I reload the page using F5).
Currently, when the page reloads, I have to re-login.
Here is my Login code:
WebContext.Current.Authentication.Login(new LoginParameters(this.UserName, this.Password, true, string.Empty),
(LoginOperation loginOperation) =>
{
if (loginOperation.LoginSuccess)
{
NotificationMessage Message = new NotificationMessage(this, null, "CLOSE");
Messenger.Default.Send<NotificationMessage>(Message);
}
}, null);
The third parameter of the Login method is the IsPersistent parameter. From the MSDN Docs, I'd think that when setting it to true, the next time I load the page, the user would still be logged in. However, this is not the case.
Do I somehow need to read a cookie which has been set internally and then login in the background with the username/password provided by that cookie? Or is there some other magic at work here?
I hope somehow has already done this.
Thanks in advance
After going through the Silverlight Business Application template, I found this line of code:
WebContext.Current.Authentication.LoadUser(this.Application_UserLoaded, null);
A good place to call it is in the Application's Startup event inside App.xaml.cs. This will load the authenticated user from the server.
I thought I'd post this if anyone happens to stumble across the same problem.
Related
Been looking into the identity server 4 solution to compliment my ASP CORE api.
Using a SPA page on front end, does IdentityServer4 have the capability to manage restfull calls for login/logout/other?
Currently my solution works perfectly to redirect to and from the IdentityServer4 solution, but wondering if i can improve on UX by avoiding the redirects that occur on login/logout?
I've heard of PopUp and iFrame capability, but from research that opens up other risks.
(not sure if this question is for stackoverflow or software engineering stack, happy to move it)
You may do this by using the resource owner password grant type, where you could provide your own login screen and pass the information to IdentityServer.
In IdentityServer you would implement the IResourceOwnerPasswordValidator interface to validate the users.
In your Startup.ConfigureServices add the following.
Services.AddTransient<IResourceOwnerPasswordValidator, ResourceOwnerPasswordValidator>();
Here is a sample ResourceOwnerPasswordValidator class.
public class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{
private IUserManager _myUserManager { get; set; }
public ResourceOwnerPasswordValidator(IUserManager userManager)
{
_myUserManager = userManager;
}
public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
{
var user = await _myUserManager.Find(context.UserName, context.Password);
if (user != null)
{
context.Result = new GrantValidationResult(
subject: user.USER_ID,
authenticationMethod: "custom",
claims: await _myUserManager.GetClaimsAsync(user));
}
else
{
context.Result = new GrantValidationResult(
TokenRequestErrors.InvalidRequest,
errorDescription: "UserName or Password Incorrect.");
}
}
}
The IUserManager implements the logic to check the database to validate the user.
Then the SPA client would use the GrantTypes.ResourceOwnerPassword. Here is an example you could start with.
DISCLAIMER
This is not the recommended flow to use.
I need to ebed a web browser in a Wpf app, I tried with the one from the toolbox but get some issues and went to CefSharp.
public MainWindow()
{
InitializeComponent();
BrowserSettings settings = new BrowserSettings();
Cef.Initialize(new CefSettings());
CefSharp.Wpf.ChromiumWebBrowser webBrowser = new CefSharp.Wpf.ChromiumWebBrowser();
licence_grid.Children.Add(webBrowser);
webBrowser.Address = "http://myurlToLoad the page";
}
The problem is when I used a normal url the page load.
But when I used the url I intend to use and whith which the user enter his user and password in a browser pop up (I mean not a pop up from the website) . I get an error with this page take yoo much time to load and nothing else.
Can someone give me some tracks to follow...
Thanks
It sounds like the popup you are referring to is in fact the site prompting for basic authentication.
In that case you need to provide an IRequestHandler.GetAuthCredentials handler.
As the question & answer is very old and i would like to give the latest update on this solution, there is slight change as per original solution suggested.
anybody consuming cefsharp need to implement the authentication dialog. and changes in method is
bool IRequestHandler.GetAuthCredentials(IWebBrowser browserControl, IBrowser browser, IFrame frame, bool isProxy,
string host, int port, string realm, string scheme, IAuthCallback callback)
{
//NOTE: If you do not wish to implement this method returning false is the default behaviour
// We also suggest you explicitly Dispose of the callback as it wraps an unmanaged resource.
// shyam - original implemenation.
//callback.Dispose();
//return false;
bool handled = false;
// Instantiate the dialog box
AuthDialog dlg = new AuthDialog(host); // create new dialog with username and password field.
// Open the dialog box modally
dlg.ShowDialog();
if (dlg.DialogResult == System.Windows.Forms.DialogResult.OK)
{
// The user did not cancel out of the dialog. Retrieve the username and password.
callback.Continue(dlg.UserName,dlg.Password);
handled = true;
}
return handled;
}
I've been able to find lots of stuff about using the ASP .NET Membership provider in WPF. I've even got the ASP .NET Role provider working in my WPF application. These are very easy to use in WPF. What I can't find any information about is how to use the ASP .NET PROFILE provider in a WPF application.
My application will be running on a laptop located in a moving vehicle; it cannot use Web Services to connect to a server and authenticate the user. My code needs to be able to retrieve the user's profile information from the local database.
I've tried several times to build a class that derives from ProfileBase but nothing I've tried has worked. To elaborate, the code below is an excerpt from my latest failed attempt:
public class UserProfile : ProfileBase {
[CustomProviderData( "AlarmsToDisplay;int" )]
public int AlarmsToDisplay {
get { return (int) GetPropertyValue( "AlarmsToDisplay" ); }
set { SetPropertyValue( "AlarmsToDisplay", value ); }
}
// Other properties following the same pattern follow.
private UserProfile() { }
public static UserProfile GetUserProfile( string username ) {
return Create( username ) as UserProfile;
}
public static UserProfile GetUserProfile( string username, bool isAuthenticated ) {
return Create( username, isAuthenticated ) as UserProfile;
}
}
In this code, the method GetUserProfile( string username, bool isAuthenticated ) returns null. I believe this is because the compiler can't cast a ProfileBase to a UserProfile, even though UserProfile descends from ProfileBase. Please correct me if I'm wrong.
Can someone point me to an existing article or describe the proper way to build a user profile class that extends from ProfileBase?
I've managed to resolve this issue on my own. Here's what works:
Remove the attributes from all of the CLR properties. These do not work with the default aspnet_Profiles table.
In app.Config, you need to add an "inherits" attribute to the tag. This has to be set to the fully qualified name of your class, separated from the assembly file name (no extension) by a comma.
Once these things were done, the GetUserProfile method and the ProfileBase class's Create methods return UserProfile objects.
My question is similar to this question. I hope I can provide some more detail and context to get it answered.
So here's some context: I have a simple in-house silverlight (ver 4) app with WCF Ria services that I'm building for our small support team. It uses authentication against a third-party vended database, but all other user information, e.g. FriendlyName and Roles (only 1 role per user) comes from our own database. I'm trying to keep this simple and don't want to implement custom membership and role providers.
I have few domain service operations that I want to restrict to certain roles, so I tried using the RequiresRole attribute like so:
[RequiresRole("Admin", "HelpDesk", "Billing" )]
public RisStudyInfo GetStudyInfo(string accession) {
return ris.GetStudyInfo(accession);
}
On the client side WebContext.Current.User.IsInRole("Admin") returns true, but I always get access denied when calling the service. The RequiresAuthentication attribute works as expected.
Below is the implementation of my AuthenticationService. The User class simply inherits from UserBase and adds the FriendlyName property. Any ideas what I'm doing wrong?
[EnableClientAccess]
public class AuthenticationService : AuthenticationBase<User> {
UserDataService userData = new UserDataService();
protected override bool ValidateUser(string userName, string password) {
var auth = new DatabaseAuthenticator();
return auth.Authenticate(userName, password);
}
protected override User GetAuthenticatedUser(IPrincipal principal) {
User user = null;
if (principal.Identity.IsAuthenticated) {
user = new User();
user.FriendlyName = userData.GetFriendlyName(principal.Identity.Name);
user.Name = principal.Identity.Name;
user.Roles = GetRolesFor(user.Name);
}
return user;
}
private IEnumerable<string> GetRolesFor(string username) {
IList<string> roles = new List<string>();
string role = userData.GetRolesFor(username);
if (role != null)
roles.Add(role);
return roles;
}
Figured it out. At least 2 things wrong. First clue found here. The second clue here
1.Turns out I really do need to write a custom role provider. Only need to implement GetRolesForUser though.
public override string[] GetRolesForUser(string username) {
return new string[] { _userService.GetRolesFor(username) };
}
2.Configure the custom role provider correctly in the web.config
<roleManager cacheRolesInCookie="true" enabled="true" defaultProvider="MyRoleProvider">
<providers>
<add name="MyRoleProvider" type="MyProject.Web.Providers.MyRoleProvider, MyProject.Web"/>
</providers>
</roleManager>
I solved this one by using the local credential store to cache credentials. Whenever a local cred check fails a foreign check occurs and the cache is populated/updated. This was a trivial override of the ValidateUser method. It does mean that stale passwords continue to work until the updated password is used (it will fail locally, pass remotely and trigger an update).
This approach meant that internally everything worked as per an out of the box configuration with no need for any other mods (apart from removing the local create-a-user links).
I am trying to add to the authentication system provided in the Silverlight 4 business template as my model does not completely fit that provided in the template. I have an existing web service that performs my authentication and provides roles and also permitted operations for each role. This is the model provided by AzMan/Authentication Manager.
However, rather than just get a single role, following authentication I provide the user with a list of available roles and allow the user to select one of these roles and then get a list of operations/actions for that selected role.
The problem that I have is that I can't work out how to add new methods to the authenticationservice to allow me to get the operations for the current user, and currently selected role in order to complete the login process e.g.
public SessionInfo GetOperations(string username, string selectedRole)
{
SessionInfo sessionInfo;
using (AzManServiceClient azClient = new AzManServiceClient("AnonymousAuthentication"))
{
sessionInfo = azClient.LoginUserByUsername("msldap://CN=LiveApps,CN=Program Data,DC=HLSUK,DC=local", "AIRS", selectedRole, null, username);
}
return sessionInfo;
}
The above method is not accessible from the LoginForm.xaml.cs using WebContextBase.Current.Authentication... Only methods such as Login are visible which is even more baffling because I can't see these methods in authenticationbase. I'm completely confused. How do I add new methods to the authentication service, or should I create a new domainservice, or should I access the azman service to get the operations directly from the silverlight client.
Have you tried to Override the methods in AuthenticationBase?
Then you can expand your authenticationservice with whatever logic you want.
<EnableClientAccess()>
Public Class AuthenticationRiaService
Inherits AuthenticationBase(Of UserAccount)
Protected Overrides Function ValidateUser(ByVal userName As String, ByVal password As String) As Boolean
End Function
End Class
Also set
WebContext.Current.Authentication To your authenticationservice as found in namespace System.ServiceModel.DomainServices.Client.ApplicationServices
Sorry for stupid VB code. :D