I am working on a microservice to enable validation of an anonymous JWT token.
After validating the jwt token for different attributes (such as issuer, expiration time etc.) I need to set AnonymousAuthenticationToken in SecurityContext by executing -
SecurityContextHolder.getContext()
.setAuthentication(anonymousAuthenticationToken);
This line will be inside my filter class that is extending org.springframework.web.filter.OncePerRequestFilter.
The constructor of AnonymousAuthenticationToken takes these three arguments:-
String key,Object principal,Collection<? extends GrantedAuthority> authorities
I understand the principal is issuer of the token. How do I get values of key and authorities?
Also, is it okay to extend OncePerRequestFilter or should I extend some other filter?
AnonymousAuthenticationToken class code says:
/**
* Constructor.
*
* #param key to identify if this object made by an authorised client
* #param principal the principal (typically a <code>UserDetails</code>)
* #param authorities the authorities granted to the principal
* #throws IllegalArgumentException if a <code>null</code> was passed
*/
public AnonymousAuthenticationToken(String key, Object principal,
Collection<? extends GrantedAuthority> authorities) {
this(extractKeyHash(key), principal, authorities);
}
For every User, some roles will be defined. You can generate authorities from those roles:
private Collection<? extends GrantedAuthority> translate(List<Roles> roles) {
List<GrantedAuthority> authorities = new ArrayList<>();
if(!CollectionUtils.isEmpty(roles)){
for (Roles role : roles) {
String name = "ROLE_"+role.getRoleId().toUpperCase();
authorities.add(new SimpleGrantedAuthority(name));
}
}
return authorities;
}
"key" is basically the client secret key defined for your application to get recognized
Related
From the Spring Integration documentation (https://docs.spring.io/spring-integration/docs/5.1.7.RELEASE/reference/html/#delayer) it is not clear to me what the messageGroupId in the DelayHandler means exactly and which value I have to set there exactly (is it arbitrary?). This value does not exist in the xml configuration, but does in the Java configuration.
#ServiceActivator(inputChannel = "input")
#Bean
public DelayHandler delayer() {
DelayHandler handler = new DelayHandler("delayer.messageGroupId"); // THIS constructor parameter is not clear to me
handler.setDefaultDelay(3_000L);
handler.setDelayExpressionString("headers['delay']");
handler.setOutputChannelName("output");
return handler;
}
It is explained in the JavaDocs of that constructor:
/**
* Create a DelayHandler with the given 'messageGroupId' that is used as 'key' for
* {#link MessageGroup} to store delayed Messages in the {#link MessageGroupStore}.
* The sending of Messages after the delay will be handled by registered in the
* ApplicationContext default
* {#link org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler}.
* #param messageGroupId The message group identifier.
* #see #getTaskScheduler()
*/
public DelayHandler(String messageGroupId) {
It is not required because the groupId is based on the required id attribute:
String id = element.getAttribute(ID_ATTRIBUTE);
if (!StringUtils.hasText(id)) {
parserContext.getReaderContext().error("The 'id' attribute is required.", element);
}
...
builder.addConstructorArgValue(id + ".messageGroupId");
It is really mentioned and explained a little bit in the docs: https://docs.spring.io/spring-integration/docs/current/reference/html/messaging-endpoints.html#delayer-namespace.
The value indeed is arbitrary, but it must be unique per your application, so different delayers don't steal messages from each other.
I want to add new field description to User entity. I can't use yo jhipster:entity User because it is forbidden. So, what I have to do?
If we need to store more information concerning a user than what JHipster provides by default, a few tweaks are needed.
To illustrate this, let’s assume we want to store the user’s phone number.
Creating a new entity in a One to One relationship with JHI_User
The best way to add information that is not handled by the default JHipster User is by using composition in a new entity linked to it with a One to One relationship.
After this entity is created, let’s call it UserExtra, the best way to handle its id is by mapping it to the JHI_User’s one. This way, our UserExtra will have the same id as the User’s, accelerating the different requests. To achieve this, you will need to use the #MapsId annotation :
public class UserExtra implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private Long id;
#Column(name = "phone")
private String phone;
#OneToOne
#MapsId
private User user;
...
}
Note that the #GeneratedValue annotation on the id needs to be removed.
Updating the register HTML page to take this change into account
Now that an entity exists to store the phone number, we need to add an input in the register form to ask for the user’s phone number.
Nothing easier than that, just update webapp/app/account/register/register.html to add an input field bound to the variable already used to store the basic information (vm.registerAccount) :
<input class="form-control" id="phone" ng-model="vm.registerAccount.phone" placeholder="global.form.phone.placeholder" />
Updating ManagedUserVM
The registerAccount() function from java/com.mycompany.myapp/web/rest/AccountResource is the one receiving the request from the registration page. Its only parameter is a ManagedUserVM object containing the information initially contained in the vm.registerAccount variable from the client.
This ManagedUserVM class located in web/rest/vm has to be updated as well so that it holds the phone number sent by the client. The only thing to do here is adding the phone number attribute and its getter :
public class ManagedUserVM extends UserDTO {
// Default attributes omitted for brevity
private String phone;
...
public String getPhone() {
return phone;
}
}
Updating the registerAccount() function from AccountResource
The registerAccount() function now receives a ManagedUserVM object that also contains the phone number of the user. The only thing left to do is saving this phone number into a new UserExtra associated with the JHipster User.
To do so, we are going to add the phone parameter to the createUser() function from UserService. But first, add this parameter where this function is called in registerAccount() :
public ResponseEntity<?> registerAccount(#Valid #RequestBody ManagedUserVM managedUserVM) {
HttpHeaders textPlainHeaders = new HttpHeaders();
textPlainHeaders.setContentType(MediaType.TEXT_PLAIN);
return userRepository.findOneByLogin(managedUserVM.getLogin().toLowerCase())
.map(user -> new ResponseEntity<>("login already in use", textPlainHeaders, HttpStatus.BAD_REQUEST))
.orElseGet(() -> userRepository.findOneByEmail(managedUserVM.getEmail())
.map(user -> new ResponseEntity<>("e-mail address already in use", textPlainHeaders, HttpStatus.BAD_REQUEST))
.orElseGet(() -> {
User user = userService
.createUser(managedUserVM.getLogin(), managedUserVM.getPassword(),
managedUserVM.getFirstName(), managedUserVM.getLastName(),
managedUserVM.getEmail().toLowerCase(), managedUserVM.getLangKey(),
managedUserVM.getPhone());
mailService.sendActivationEmail(user);
return new ResponseEntity<>(HttpStatus.CREATED);
})
);
}
Updating the createUser() function from UserService
Finally, we update the service layer function that saves the JHI_User to now save the UserExtra as well. Rather than updating the existing function, I suggest you create a new one with the additional parameter. This way, updating the test classes isn’t necessary.
Do not forget to inject the UserExtra repositories :
#Inject
private UserExtraRepository userExtraRepository;
#Inject
private UserExtraSearchRepository userExtraSearchRepository;
...
public User createUser(String login, String password, String firstName, String lastName, String email,
String langKey, String phone) {
User newUser = new User();
Authority authority = authorityRepository.findOne(AuthoritiesConstants.USER);
Set<Authority> authorities = new HashSet<>();
String encryptedPassword = passwordEncoder.encode(password);
newUser.setLogin(login);
// new user gets initially a generated password
newUser.setPassword(encryptedPassword);
newUser.setFirstName(firstName);
newUser.setLastName(lastName);
newUser.setEmail(email);
newUser.setLangKey(langKey);
// new user is not active
newUser.setActivated(false);
// new user gets registration key
newUser.setActivationKey(RandomUtil.generateActivationKey());
authorities.add(authority);
newUser.setAuthorities(authorities);
userRepository.save(newUser);
userSearchRepository.save(newUser);
log.debug("Created Information for User: {}", newUser);
// Create and save the UserExtra entity
UserExtra newUserExtra = new UserExtra();
newUserExtra.setUser(newUser);
newUserExtra.setPhone(phone);
userExtraRepository.save(newUserExtra);
userExtraSearchRepository.save(newUserExtra);
log.debug("Created Information for UserExtra: {}", newUserExtra);
return newUser;
}
https://jhipster.github.io/tips/022_tip_registering_user_with_additional_information.html
Add column to entity User.java:
#Column(name = "description")
private String description;
Modify method toString().
In UserDTO.java add:
private String description;
Generate getter and modify method toString().
Add liquidbase diff or add column.
Now is time to modify some webapp folder.
File user-managment.state.js find state user-managment.new and to entity: function () new return ,description: null
If you want to add this field to display find and modify files:
user-managment.html
user-managment-detail.html
user-managment-dialog.html
For example: <th><span data-translate="some.some.user.description">Description</span></th>
I am looking for a way to create DefaultSftpSessionFactory using private key string. The different functions available in this are using the private Key Resource(local file) instead.
Any ideas to create SessionFactory needed for SftpRemoteFileTemplate? I have the user, host and the private key as a String.
-Thanks
The setter takes a Resource...
/**
* Allows you to set a {#link Resource}, which represents the location of the
* private key used for authenticating against the remote host. If the privateKey
* is not provided, then the {#link DefaultSftpSessionFactory#setPassword(String) password}
* property is mandatory (or {#link #setUserInfo(UserInfo) userInfo} that returns a
* password.
* #param privateKey The private key.
* #see JSch#addIdentity(String)
* #see JSch#addIdentity(String, String)
*/
public void setPrivateKey(Resource privateKey) {
this.privateKey = privateKey;
}
There are many kinds of Resource, including ByteArrayResource, where you can use
setPrivateKey(new ByteArrayResource(myKeyString.getBytes());
I'm creating an Azure Mobile Service using Entity Framework Code First and trying to follow the [Class]Id naming convention for Keys. My goal is to have the [Class]Id column be the sole Primary Key and not have any Id column created. I can't seem to get that to happen. When I scaffold a new Azure Table Controller from the following, the generated code creates ClientId, but also creates Id. When I test the code I get the error "Unable to determine composite primary key ordering..." because (I assume) I'm not addressing the Column Order of Id since it doesn't even appear in the Class.
public class Client: EntityData
{
// Unique ID of this client (PK)
[Key, Column(Order = 1), Required, DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid ClientId { get; set; }
(...)
}
Not sure it's relevant, but note that I am setting the value of ClientId and not asking the db to auto-set it for me.
What have I missed? Thanks!
Your Client class is inheriting from EntityData which already contains a Primary Key called Id
Public class EntityData : ITableData
{
[Key]
[TableColumn(TableColumnType.Id)]
public string Id { get; set; }
//Other system properties
}
You could remove the EntityData and setup your own keys etc but you may run into more problems than its worth with Azure Mobile Services
I am creating an application using seam 3 and cdi. I started with an example, for the security part like this:
public #ConversationScoped class UserAction {
public #Admin void deleteUser(String userId) {
// code
}
}
It works. If my user has the admin role, then he has access. But how can I implement a situation where the user may have one rule or the other? For example: if my user is #Admin or #Student he can access this, but if he is a #Teacher he cannot.
Thanks.
Kelly
I think you need to create your own authorizer method which does the specific role checks you need:
import org.jboss.seam.security.annotations.Secures;
public class Restrictions {
public #Secures #Admin boolean isAdmin(Identity identity) {
return identity.hasRole("admin", "USERS", "GROUP");
// Here, you would put in logic for "if my user is
// #Admin or #Student he can access this, but
// if he is a #Teacher he cannot" instead.
}
}