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);
}
Related
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.
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().
I'm trying to add roles and permissions when a new user is registered. I'm running into the problem that adding to the session roles and permissions does not get persisted to the database.
I've written a Custom AuthUserSession and overridden OnAuthenticated.
The code below uses the AssignRolesService, and that seems like it would be exactly what I need except for one problem. When the authentication is handled by Facebook auth provider session.UserAuthName is null so I can't call the service.
To clarify, all code snippets below are contained within:
public override void OnAuthenticated(IServiceBase authService, IAuthSession session,
IOAuthTokens tokens, Dictionary<string, string> authInfo)
The suggested way of doing this (from what I found on SO/Google):
using (var assignRoles = authService.ResolveService<AssignRolesService>())
{
assignRoles.Post(new AssignRoles {
UserName = session.UserAuthName,
Roles = { RoleNames.Admin }
});
}
Also tried this but it did not work:
session.Roles.Add("user");
session.Permissions.Add("setup");
authService.SaveSession(session);
The only thing that I found that seems to work, but seems like a hack is:
UserAuth ua = db.GetById<UserAuth>(session.UserAuthId);
ua.UserName = user.Email;
ua.Roles.Add("user");
ua.Permissions.Add("setup");
db.Save(ua);
Hi I just figured it out!
if just by a a coincidence you're using LoadUserInfo that have a try / catch when you are trying to assign the values, hiding a null reference exception and doing the redirect without doing a re-throw
that got fixed just by creating a new List like this:
userSession.Roles = new List<string> {"your-role-here"};
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)
What is the best way to pass the model variables to layout in Grails? Specifically, I'm using Spring security plugin which has User class. I also have Contact class that looks like this:
class Contact {
String realname
String company
String mobile
String fix
String email
User user
...
What are the options for getting the currently logged in person's company in my layout (main.gsp)?
To add to the above answer, you could alternatively set a session variable for the user when you login in whatever controller method gets called.
You can also just set a session variable for the company in the controller method:
session.company = Contact.findByUser(session.user)?.company
or from the example above
session.company = Contact.findByUser(SecurityContextHolder.context.authentication?.principal)?.company
And in your main.gsp, something like:
<span id="companyName">${session.company}</span>
Do you mean that you need to pass this model for every page, automatically, instead of manual passing it at render at each of controllers? You can use filters there:
def filters = {
all(controller: '*', action: '*') {
before = {
request.setAttribute('loggedInPerson', SecurityContextHolder.context.authentication?.principal)
//Notice, that there is used original Authentication, from Spring Security
//If you need you can load your Contact object there, or something
}
after = {
}
afterView = {
}
}
}
and use loggedInPerson at your gsp:
Hello ${loggedInPerson.username}!
Btw, there is also Spring Security tags, that can help you without using your own filter, like:
Hello <sec:loggedInUserInfo field="username"/>!
If you want to add a certain object to the model, you can also use the "interceptors" provided by grails. To add a certain variable to a particular controller, you can use something like this.
def afterInterceptor = {model, modelAndView->
model.loggedInUser = getLoggedInUser() // retrieve your user details here
}
And you can retrieve loggedInUser in the main.gsp layout as ${loggedInUser}.
If you need to get these details in multiple controllers, you can create a BaseController and keep the afterInterceptor in this BaseController. All controllers which need the reference to the logged in user in their corresponding views should extend the BaseController.