I've implemented custom authentication in my mobile services, but the claims that I add to my ClaimsIdentity object don't appear to be saved.
I create my ClaimsIdentity object, and then pass it to the CreateLoginResult method, as follows:
public IServiceTokenHandler Handler { get; set; }
...
ClaimsIdentity claimsIdentity = new ClaimsIdentity();
claimsIdentity.AddClaim(new Claim(ClaimTypes.NameIdentifier, "username"));
claimsIdentity.AddClaim(new Claim(ClaimTypes.GivenName, "FirstName"));
claimsIdentity.AddClaim(new Claim(ClaimTypes.Surname, "LastName"));
LoginResult login = new CustomLoginProvider(Handler).CreateLoginResult(claimsIdentity, "masterkey");
If I call another method with the returned authorization token and try to retrieve the GivenName or Surname claims, they aren't available.
var identity = (ClaimsIdentity)User.Identity;
// 'claim' will be null
Claim claim = identity.FindFirst(ClaimTypes.GivenName);
Is this expected behaviour or am I doing something wrong? I'm making an assumption that the Claims in the ClaimsIdentity object being sent to CreateLoginResult are being saved against that authenticated user.
The ClaimsIdentity passed into this method does not get used fully unless you act on it in an overload of CreateCredentials(). First you should create a child class of ProviderCredentials with the fields you want. CreateCredentials() will be called by CreateLoginResult(), and it will get the same ClaimsIdentity as a parameter.
The returned ProviderCredentials gets stored, and you can always retrieve it again in your server code with a call to ServiceUser.GetIdentitiesAsync().
Related
I want to use a user attribute as a flag during the Keycloak authentication flow. How can I change the value of a user attributes in java (not using the api)? How do I reference that attribvute in a template (ftl file)
Thanks for any guidance.
How do I reference that attribute in a template (ftl file)
I think accessing to user attrs should be disabled by default.
Solution: Set user attribute as form attribute.
Code for Form:
#Override
protected Response createLoginForm(LoginFormsProvider form) {
form.setAttribute("customattr", user.getFirstAttribute("customattr"));
return form.createForm("your-page.ftl");
}
And in ftl:
<label>${customattr}</label>
Add or update a single attribute to a Keycloak-User like this:
#Transactional
public void setAttributeByAuthentication(String attributeName, String attributeValue, Authentication auth) {
// Get realm.
RealmResource realmResource = this.getRealmResource();
// Get Keycloak user based on current authentication.
UserResource userResource = realmResource.users().get(this.getAccessTokenByAuthentication(auth).getSubject());
UserRepresentation user = userResource.toRepresentation();
user.singleAttribute(attributeName, attributeValue);
userResource.update(user);
}
Can we customize the scope in GoogleAuthProvider to get more details like their phone number, address or calendar, profile picture?
Also can we view the details of the Identity and access token and parse and save those results in our database?
You can register additional Scopes in the GoogleAuthProvider.Scopes collection which by default is populated with:
this.Scopes = new[] {
"https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/userinfo.email"
};
The OAuth Info from all ServiceStack's OAuth Providers are populated in the registered Auth Repository in the UserAuthDetails table where the Access Token is stored in AccessTokenSecret.
You can retrieve additional info about the user using the Access Token and overriding CreateAuthInfo in a custom GoogleAuthProvider and overriding the CreateAuthInfo() implementation which by default retrieves basic info about the user from the UserProfileUrl (https://www.googleapis.com/oauth2/v2/userinfo):
protected override Dictionary<string, string> CreateAuthInfo(string accessToken)
{
var url = this.UserProfileUrl.AddQueryParam("access_token", accessToken);
var json = url.GetJsonFromUrl();
var obj = JsonObject.Parse(json);
obj.MoveKey("id", "user_id");
obj.MoveKey("given_name", "first_name");
obj.MoveKey("family_name", "last_name");
obj.MoveKey("picture", AuthMetadataProvider.ProfileUrlKey, profileUrl => profileUrl.SanitizeOAuthUrl());
return obj;
}
The returned dictionary populates all well-known properties on UserAuthDetails in the overridable LoadUserAuthInfo() (which can alternatively be intercepted with the LoadUserAuthFilter on each AuthProvider). All other non-matching properties in the dictionary are saved in the Items Dictionary on the UserAuthDetails table.
We protect action with authorize attribute with specific role name this way
[Authorize(Roles="members, admin")]
suppose users and roles are mapped in db table. so when user login then how could i attach role with logged in user using identity.
here i am posting url and sample which show how people do the same in mvc4 with custom form authentication. just see the code and i hope surely understand what i am trying to do with asp.net mvc 5 using identity.
https://www.codeproject.com/Articles/408306/Understanding-and-Implementing-ASP-NET-Custom-Form
see this above url for custom form authentication with asp.net mvc 4
protected void FormsAuthentication_OnAuthenticate(Object sender, FormsAuthenticationEventArgs e)
{
if (FormsAuthentication.CookiesSupported == true)
{
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
try
{
//let us take out the username now
string username = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
//let us extract the roles from our own custom cookie
string roles = DBHelper.GetUserRoles(username);
//Let us set the Pricipal with our user specific details
e.User = new System.Security.Principal.GenericPrincipal(
new System.Security.Principal.GenericIdentity(username, "Forms"), roles.Split(';'));
}
catch (Exception)
{
//somehting went wrong
}
}
}
}
i am working with asp.net mvc 5 & identity system. please help and guide me. thanks
You have to get logged in user id first
var UserName= await User.Identity.GetUserId()
then you can assign any role to that logged in user like
var _context = new ApplicationDbContext();
var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(_context));
UserManager.AddToRole("UserName", "UserRole");
Core 2.0, using AspnetCore.Identity. I created a few roles, including "Admin".
//initializing custom roles
var RoleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
var UserManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
string[] roleNames = { "Admin", "Training", "Operations", "Membership", "Individual" };
IdentityResult roleResult;
foreach (var roleName in roleNames)
{
var roleExist = await RoleManager.RoleExistsAsync(roleName);
// ensure that the role does not exist
if (!roleExist)
{
//create the roles and seed them to the database:
roleResult = await RoleManager.CreateAsync(new IdentityRole(roleName));
}
}
I checked the SQL tables, and they're all there.:
Then I add myself to the Admin role (not the full method, but the relevant parts):
var UserManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
var _eric = await UserManager.FindByEmailAsync("username#gmail.com");
await UserManager.AddToRoleAsync(_eric, "Admin");
I check the tables, and I'm in there (along with another guy I added to a different role):
I then travel over to my method and slap Authorize on it with two of the roles, one of which I'm in (Admin):
[Authorize(Roles ="Training, Admin")]
public ActionResult Index()
{
return View();
}
And then I get access denied. I'm missing something, but can't figure out what step I messed up. User is in there, I'm logged in, the data tables show me as having the role assigned, and the Authorize tag looks good.
Roles are claims and claims are loaded only on sign in. If you modify a claim (such as by adding a role), you must sign the user out and either automatically sign them back in or prompt the user to re-authenticate, to reload the claims.
I am working on Integrating spring security with openId for my grails Application using springsecurity core and springsecurity openid plugins. I have integrated it, and it works well but I need to access the email for the logged in person. How can I get that, all that I am able to access is a token which is used for identifying the person.
Thanks to Ian Roberts.
He gives me this reply,Which exactly solves my problem.
His reply was:
As it happens I implemented exactly this in one of my applications
yesterday :-) Unfortunately it's not an open-source app so I can't just
point you at my code but I can explain what I did.
The spring-security-openid plugin supports the "attribute exchange"
mechanism of OpenID, although the support is not documented much (if at
all). How well it works depends on the provider at the far end but this
at least worked for me using Google and Yahoo.
In order to request the email address from the provider you need to add
the following to Config.groovy:
grails.plugins.springsecurity.openid.registration.requiredAttributes.email
= "http://axschema.org/contact/email"
Now to wire that into your user registration process you need an email
field in your S2 user domain class, and you need to edit the generated
OpenIdController.groovy in a few places.
add an email property to the OpenIdRegisterCommand
in the createAccount action there's a line
"if(!createNewAccount(...))" which passes the username, password and
openid as parameters. Change this along with the method definition to
pass the whole command object instead of just these two fields.
in createNewAccount pass the email value forward from the command
object to the User domain object constructor.
And finally add an input field for email to your
grails-app/views/openId/createAccount.gsp.
You can do the same with other attributes such as full name.
grails.plugins.springsecurity.openid.registration.requiredAttributes.fullname
= "http://axschema.org/namePerson"
The important thing to wire it together is that the thing after the last
dot following requiredAttributes (fullname in this example) must match
the name of the property on the OpenIdRegisterCommand.
Regards
Charu Jain
I've never used the springsecurity openid plugin, but when using springsecurity core you can expose additional information about the current user by implmenting a custom UserDetails. In my app, I added this implementation, so that I can show the name property of logged-in users. You'll need to change this slightly, so that the email address is exposed instead
/**
* Custom implementation of UserDetails that exposes the user's name
* http://grails-plugins.github.com/grails-spring-security-core/docs/manual/guide/11%20Custom%20UserDetailsService.html
*/
class CustomUserDetails extends GrailsUser {
// additional property
final String name
CustomUserDetails(String username,
String password,
boolean enabled,
boolean accountNonExpired,
boolean credentialsNonExpired,
boolean accountNonLocked,
Collection<GrantedAuthority> authorities,
long id,
String displayName) {
super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities, id)
this.name = displayName
}
}
You then need to create a custom implementation of UserDetailsService which returns instances of the class above
class UserDetailsService implements GrailsUserDetailsService {
/**
* Some Spring Security classes (e.g. RoleHierarchyVoter) expect at least one role, so
* we give a user with no granted roles this one which gets past that restriction but
* doesn't grant anything.
*/
static final List NO_ROLES = [new GrantedAuthorityImpl(SpringSecurityUtils.NO_ROLE)]
UserDetails loadUserByUsername(String username, boolean loadRoles) {
return loadUserByUsername(username)
}
UserDetails loadUserByUsername(String username) {
User.withTransaction { status ->
User user = User.findByUsername(username)
if (!user) {
throw new UsernameNotFoundException('User not found', username)
}
def authorities = user.authorities.collect {new GrantedAuthorityImpl(it.authority)}
return new CustomUserDetails(
user.username,
user.password,
user.enabled,
!user.accountExpired,
!user.passwordExpired,
!user.accountLocked,
authorities ?: NO_ROLES,
user.id,
user.name)
}
}
}
You need to register an instance of this class as a Spring bean named userDetailsService. I did this by adding the following to Resources.groovy
userDetailsService(UserDetailsService)