How to create a new Authority in jHipster? - jhipster

I wonder if it is possible to create a new Authority in Jhispter. I tried adding a ROLE_WRITER:
/project/src/main/java/location/security/AuthoritiesConstants.java
package location.security;
/**
* Constants for Spring Security authorities.
*/
public final class AuthoritiesConstants {
public static final String ADMIN = "ROLE_ADMIN";
public static final String USER = "ROLE_USER";
public static final String WRITER = "ROLE_WRITER";
public static final String ANONYMOUS = "ROLE_ANONYMOUS";
private AuthoritiesConstants() {
}
}
When I run the app, it does not crash, but when I tried to change the localhost:9000/#/user-management ROLE in the profile, it did not offer me the option.
So I went to the database and add a new ROLE in the JHI_AUTHORITY Table and now it appears in the user-management, but I have the feeling that i'm getting into trouble if I mess around with the User Entity.
Is there any official way of doing it? (that I am not aware of)
Is there any danger with doing it?
Is there anything else that I should consider?
Thanks

Is there any official way of doing it? (that I am not aware of)
Have you seen src/main/resources/liquibase/authorities.csv? I think that is a right place to add a new authority before production, and when you are in production stage, then it is recommended to add your change(insert into) as liquibase changeset.
Is there any danger with doing it?
AFAIK new role will work like other existing roles in Spring security context. having said that I might misunderstood your question.
Is there anything else that I should consider?
Automation, this type of manual changes will cause dysfunction in production or new installation, so we need to automate this type of changes for both situations.

Although this is already answered, I think it's a good idea to put a link to a related tip posted in the official website of JHipster:
https://www.jhipster.tech/tips/025_tip_create_new_authority.html

I faced the same issue, I added drop-first: true parameter to src/main/resources/config/application-dev.yml:
....
liquibase:
contexts: dev
drop-first: true
....
It seems like it ais a parameter to regenerate the database (for development mode).

Related

Fixing "PrincipalException: PermissionChecker not initialized" the Liferay 7 way

With Liferay 6, using *LocalServiceUtil static calls was common. Starting from Liferay 7, these calls should be avoided in favor of #Referenceing the OSGi service and using it as a private member of the class, if I understood correctly (feel free to correct me).
Problem: When I replace my old *LocalServiceUtil calls with the OSGi-friendly equivalent, I get this exception:
com.liferay.portal.kernel.security.auth.PrincipalException:
PermissionChecker not initialized
at com.liferay.portal.kernel.service.BaseServiceImpl.getPermissionChecker
at com.liferay.portal.service.impl.UserServiceImpl.getUserById
How to fix it?
I could get a random admin via the OSGi equivalent of UserLocalServiceUtil.getRoleUsers(RoleLocalServiceUtil.getRole(company.getCompanyId(),"Administrator").getRoleId()) and use it in the the OSGi equivalent of PermissionThreadLocal.setPermissionChecker(PermissionCheckerFactoryUtil.create(randomAdmin)) but that sounds very hacky, plus it would put the responsibility of my code's actions on the shoulders of this unlucky admin.
My code:
protected void myMethod() {
userService.getUserById(userId);
}
#Reference(unbind = "-")
protected com.liferay.portal.kernel.service.UserService userService;
I think you actually wanted to inject UserLocalService.
In OSGi you should only strip the *Util suffix to receive equivalent functionality.
What you did is moved from LocalService (UserLocalServiceUtil) to remote service (UserService). The local services do not check permissions so there is no permission checker initialisation.
Apart from the above, you should be sure that no mischief can happen when using Local services. It's not recommended to expose this kind of functionality to end users but it's fine for some background processing.

I wrote a Liferay module. How to make it configurable by administrators?

I have created a Liferay 7 module, and it works well.
Problem: In the Java source code I hard-coded something that administrators need to modify.
Question: What is the Liferay way to externalize settings? I don't mind if the server has to be restarted, but of course the ability to modify settings on a live running server (via Gogo Shell?) could be cool provided that these settings then survive server restarts.
More specifically, I have a module for which I would like to be able to configure an API key that looks like "3g9828hf928rf98" and another module for which I would like to configure a list of allowed structures that looks like "BASIC-WEB-CONTENT","EVENTS","INVENTORY".
Liferay is utilizing the standard OSGi configuration. It's quite a task documenting it here, but it's well laid out in the documentation.
In short:
#Meta.OCD(id = "com.foo.bar.MyAppConfiguration")
public interface MyAppConfiguration {
#Meta.AD(
deflt = "blue",
required = false
)
public String favoriteColor();
#Meta.AD(
deflt = "red|green|blue",
required = false
)
public String[] validLanguages();
#Meta.AD(required = false)
public int itemsPerPage();
}
OCD stands for ObjectClassDefinition. It ties this configuration class/object to the configurable object through the id/pid.
AD is for AttributeDefinition and provides some hints for the configuration interface, which is auto-generated with the help of this meta type.
And when you don't like the appearance of the autogenerated UI, you "only" have to add localization keys for the labels that you see on screen (standard Liferay translation).
You'll find a lot more details on OSGi configuration for example on enroute, though the examples I found are always a bit more complex than just going after the configuration.

MVC5, OWIN, and Ninject - GetOwinContext Issues

I have an MVC5 project that is doing OwinStartup, and I'm using Ninject.MVC5, Ninject.Web.Common.OwinHost, etc.
I have NinjectWebCommon bootstrapping DI and things were working just fine. Until I started playing with the identity code.
I need to issue a password reset token, which requires a DataProtectionProvider. No problem, the ApplicationUserManager wires that up in the Create method, which is bound to the OwinContext during startup in Startup.Auth.cs:
public void ConfigureAuth(IAppBuilder app)
{
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
...
}
In my NinjectWebCommon I have the following registrations:
kernel.Bind<IDataContext>()
.ToMethod(ctx => HttpContext.Current.GetOwinContext().Get<ApplicationDbContext>())
.InRequestScope();
kernel.Bind<IApplicationUserManager>()
.ToMethod(ctx => HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>())
.InRequestScope();
The problem I'm having is that the token isn't being issued. Why isn't that what my question is about? Well, if I get an instance of the ApplicationUserManager using the Create myself and use that, things work flawlessly.
Next on my plate a reported user creation bug. Hyphens aren't working in usernames. In that same ApplicationUserManager.Create method, is the UserValidator code that's overriding the default AllowOnlyAlphanumericUserNames value.
Again, if I use a self created dependency, it works as expected. This seems to indicate Ninject's injected dependency isn't using the ApplicationUserManager.Create'd version.
I'm guessing this has to do with the call to: HttpContext.Current.GetOwinContext??
Is there something I need to do in order to inject something that relies on the owin context or something else I need to do while registering my resolver?
I've seen other questions here showing UseNinjectMiddleware and UseNinjectWebApi. I tried that approach, but didn't have any luck, nothing was being injected in...
Any assistance is greatly appreciated!

Can ACS Service Namespace creation be automated?

First, let me state my real problem: I've got code that makes calls to the ACS Management service, and I'd like my integration tests to be able to be run concurrently without each test run clobbering the others. That is, since multiple people / build servers might end up running these tests concurrently, if they're all using the same ACS service namespace, concurrency issues arise.
My thinking is the simplest means of achieving this would be to generate new, unique ACS service namespaces for each test runner -- but as far as I can tell, there's no automated way of creating new service namespaces (or management client keys). Am I wrong? Is there another way of going about this?
An automated method of creating new service namespaces would be extraordinarily helpful.
You are correct. That's not possible today. Maybe you can describe your scenario in more detail and there might be some alternative solutions to avoid having to recreate the namespace?
Technically it should be possible, since the Management Portal is a Silverlight application accessing a WCF RIA Service.
If you dig deep enough you'll find some useful information:
This is the Silverlight XAP for the management of Windows Azure AppFabric: https://appfabricportal.windows.azure.com/ClientBin/Microsoft.AppFabric.WebConsole.4.1.3.xap
This is the service being used when listing/creating/... namespaces etc..: https://appfabricportal.windows.azure.com/Services/Microsoft-AppFabric-Web-Services-AppFabricDomainService.svc?wsdl
And this is a piece of the DomainContext:
public sealed class AppFabricDomainContext : DomainContext
{
public AppFabricDomainContext(Uri serviceUri)
: this((DomainClient) new WebDomainClient<AppFabricDomainContext.IAppFabricDomainServiceContract>(serviceUri, true))
{
}
...
public InvokeOperation CreateServiceNamespace(IEnumerable<string> serviceNames, string parentProjectKey, string serviceNamespace, IEnumerable<string> packageKeys, string regionKey, Action<InvokeOperation> callback, object userState)
{
Dictionary<string, object> dictionary = new Dictionary<string, object>();
dictionary.Add("serviceNames", (object) serviceNames);
dictionary.Add("parentProjectKey", (object) parentProjectKey);
dictionary.Add("serviceNamespace", (object) serviceNamespace);
dictionary.Add("packageKeys", (object) packageKeys);
dictionary.Add("regionKey", (object) regionKey);
this.ValidateMethod("CreateServiceNamespace", (IDictionary<string, object>) dictionary);
return this.InvokeOperation("CreateServiceNamespace", typeof (void), (IDictionary<string, object>) dictionary, true, callback, userState);
}
}
Finding this info was the easy part, getting it to work... that's something else. Take the authentication part for example, you'll need to authenticate with Windows Live and use those credentials when calling the WCF RIA Service.
Good luck!

Do I must expose the aggregate children as public properties to implement the Persistence ignorance?

I'm very glad that i found this website recently, I've learned a lot from here.
I'm from China, and my English is not so good. But i will try to express myself what i want to say.
Recently, I've started learning about Domain Driven Design, and I'm very interested about it. And I plan to develop a Forum website using DDD.
After reading lots of threads from here, I understood that persistence ignorance is a good practice.
Currently, I have two questions about what I'm thinking for a long time.
Should the domain object interact with repository to get/save data?
If the domain object doesn't use repository, then how does the Infrastructure layer (like unit of work) know which domain object is new/modified/removed?
For the second question. There's an example code:
Suppose i have a user class:
public class User
{
public Guid Id { get; set; }
public string UserName { get; set; }
public string NickName { get; set; }
/// <summary>
/// A Roles collection which represents the current user's owned roles.
/// But here i don't want to use the public property to expose it.
/// Instead, i use the below methods to implement.
/// </summary>
//public IList<Role> Roles { get; set; }
private List<Role> roles = new List<Role>();
public IList<Role> GetRoles()
{
return roles;
}
public void AddRole(Role role)
{
roles.Add(role);
}
public void RemoveRole(Role role)
{
roles.Remove(role);
}
}
Based on the above User class, suppose i get an user from the IUserRepository, and add an Role for it.
IUserRepository userRepository;
User user = userRepository.Get(Guid.NewGuid());
user.AddRole(new Role() { Name = "Administrator" });
In this case, i don't know how does the repository or unit of work can know that user has a new role?
I think, a real persistence ignorance ORM framework should support POCO, and any changes occurs on the POCO itself, the persistence framework should know automatically. Even if change the object status through the method(AddRole, RemoveRole) like the above example.
I know a lot of ORM can automatically persistent the changes if i use the Roles property, but sometimes i don't like this way because of the performance reason.
Could anyone give me some ideas for this? Thanks.
This is my first question on this site. I hope my English can be understood.
Any answers will be very appreciated.
Should the domain object interact with repository to get/save data?
No, it should not. Reason for that is simple - encapsulation. If we take away everything persistence related from our domain model, we can describe our domain much clearer.
If the domain object doesn't use repository, then how does the Infrastructure layer (like unit of work) know which domain object is new/modified/removed?
Simplest version is - it doesn't. You retrieve and save it back (after operation on aggregate has completed) as a whole:
var user = users.Find(guid);
user.AssignRole(Role.Administrator);
users.Save(user);
I personally rely on NHibernate - it tracks changes itself. If I optimize queries with proper eager/lazy loading, save changes only on http request end, don't forget about transactions, use caching - there is no performance penalty. But for a price - it takes some knowledge to handle that.
One more thing - think twice before using domain driven design for development of forum. This approach fits only for unknown (yet) and complex business domains. It's an overkill for simple applications.
And another thing - stop being ashamed of Your English. It will get better in no time. :)

Resources