SQL Permission with Java Authentication and Authorization Service - java

I have a SQL table user with 2 roles: ADMIN and USER.
I'm trying to use Java Authentication and Authorization Service(jaas) to make user with ADMIN role can read and modify other tables while USER role can read only.
I create a custom class extent java.security.Permission and a custom class extend
Policy class but I can't find any way to check permission with SecurityManager
PolicyImpl policy = new PolicyImpl();
Policy.setPolicy(policy);
Subject subject = loginContext.getSubject();
try {
Subject.doAsPrivileged(subject, (PrivilegedAction) () -> {
SecurityManager sm = System.getSecurityManager();
sm.checkSecurityAccess();
if (sm != null) {
sm.checkPermission(); // I don't know how to make this function check for
// SQL permission based on custom policy
}
return null;
}, null);
My Policy class
public class PolicyImpl extends Policy {
#Override
public PermissionCollection getPermissions(ProtectionDomain domain) {
List<Principal> principals = Arrays.asList(domain.getPrincipals());
if (principals.isEmpty()) {
return null;
}
BasicPermission basicPermission = null;
try {
for (Principal principal : principals) {
basicPermission = (BasicPermission) AccessController
.doPrivileged((PrivilegedExceptionAction) () -> Controller.getRoles(principal.getName()));
}
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
return basicPermission.newPermissionCollection();
}
}
It seems that java.security.FilePermission is the most suitable one since this permission has read and write property but I don't know how can I use this class for SQL Server.

Related

Implementing the password owner resource flow of OAuth2 in Play (Java)

For my Bachelor's-thesis I have to implement different kinds of Authentication and Authorization with different Frameworks.
Currently im at the OAuth2 chapter and have to implement it in the Play Framework (in Java). (I have already implemented it with Spring Boot)
While researching on how to approach this Problem, so far, I could not find a lot of helpful tips.
One of the main Questions I have is: after the Client authenticatet itselfe with the users credentials and has gotten the Token, how do I best verify the Token?
Basicly: What is the Play- counterpart to the "#PreAuthorize" annotation of Spring?
Any tip or link to a helpful website is appreciated.
So I think I solved my Problem. On the off chance that someone stumbles on the same question I'm gonna post the solution here:
As written in the Play-Docs (https://www.playframework.com/documentation/2.6.x/JavaOAuth) with OAuth2 and especially with the Password flow it is pretty simple.
First you need an Authorization-Service, here the implementation is straight forward. Just implement three methods:
POST /oauth/token for passing the user-credentials and recieving an access- and refresh-token
POST /oauth/refresh for when the access-token is no longer valid. Here the refresh-token is passed and a new acces token returned
POST /oauth/check_token for authorization. Here the access Token is passed and in my case I return the role, the user has. Alternativly it would also be possible and maybe eaven better to do the authorization process in the authorization-service. For this you would need to change the "check_token" method and pass the required role.
I just generated uuids as tokens and stored them in a database. I guess one could also use for example jwts and put the needed information (for example the expiration date) in the token.
Then my main question was about the annotations. I found this
https://github.com/bekce/oauthly
and just lookt at their implementation.
You basicly just need a class and a interface:
The Interface:
#With(AuthorizationServerAuthAction.class)
#Target({ElementType.TYPE, ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
public #interface AuthorizationServerSecure {
boolean requireAdmin() default false;
boolean requirePersonnel() default false;
boolean requireGuest() default false;
}
The Class:
private WSClient ws;
private final String url = "http://localhost:9001/oauth/check_token";
#Inject
public AuthorizationServerAuthAction(WSClient ws) {
this.ws = ws;
}
private CompletionStage<JsonNode> callApi(String accessToken) {
CompletionStage<WSResponse> eventualResponse = ws.url(url).setContentType("application/x-www-form-urlencoded").setRequestTimeout(Duration.ofSeconds(10))
.addHeader("Authorization" , accessToken).post("none");
return eventualResponse.thenApply(WSResponse::asJson);
}
#Override
public CompletionStage<Result> call(Http.Context ctx) {
Optional<String> accessTokenOptional = ctx.request().header("Authorization");
JsonNode result = null;
if(!accessTokenOptional.isPresent()){
return CompletableFuture.completedFuture(unauthorized(Json.newObject()
.put("message", "No token found in header!")
));
}
CompletionStage<JsonNode> apiResponse = callApi(accessTokenOptional.get());
try {
result = apiResponse.toCompletableFuture().get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
if(result == null) {
return CompletableFuture.completedFuture(unauthorized(Json.newObject()
.put("message", "an error occurred")
));
}
String role = result.get("role").asText();
if(configuration.requireAdmin()){
if(role.equals("admin")) {
return delegate.call(ctx);
} else {
return CompletableFuture.completedFuture(unauthorized(Json.newObject()
.put("message", "The user is not authorized to perform this action!")
));
}
} else if(configuration.requirePersonnel()) {
if(role.equals("personnel") || role.equals("admin")) {
return delegate.call(ctx);
} else {
return CompletableFuture.completedFuture(unauthorized(Json.newObject()
.put("message", "The user is not authorized to perform this action!")
));
}
} else if(configuration.requireGuest()) {
if(role.equals("guest") || role.equals("personnel") || role.equals("admin")) {
return delegate.call(ctx);
} else {
return CompletableFuture.completedFuture(unauthorized(Json.newObject()
.put("message", "The user is not authorized to perform this action!")
));
}
}
return CompletableFuture.completedFuture(unauthorized(Json.newObject()
.put("message", "an error occurred")
));
}
}

How to create user and group in aem6.2 programmatically with ACL permissions?

Is it possible to create Group and User in AEM6.2 by using Jackrabbit User Manager API with permissions.
I have just followed below URL's but the code is throwing some exception :
https://helpx.adobe.com/experience-manager/using/jackrabbit-users.html
https://stackoverflow.com/questions/38259047/how-to-give-permission-all-in-aem-through-programatically
ResourceResolverFactory getServiceResourceResolver throws Exception in AEM 6.1
As getAdministrativeResourceResolver(Map) method is deprecated then how can we use getServiceResourceResolver(Map) method instead.
Sharing my solution which will be helpful for others.
Following is the code using getServiceResourceResolver(Map) method for creating Group first and then User and then add user into group with ACL privileges and permission:
public void createGroupUser(SlingHttpServletRequest request) {
String userName = request.getParameter("userName");
String password = request.getParameter("password");
String groupName = request.getParameter("groupName");
Session session = null;
ResourceResolver resourceResolver = null;
try {
Map<String, Object> param = new HashMap<String, Object>();
param.put(ResourceResolverFactory.SUBSERVICE, "datawrite");
resourceResolver = resourceResolverFactory.getServiceResourceResolver(param);
session = resourceResolver.adaptTo(Session.class);
// Create UserManager Object
final UserManager userManager = AccessControlUtil.getUserManager(session);
// Create a Group
Group group = null;
if (userManager.getAuthorizable(groupName) == null) {
group = userManager.createGroup(groupName);
ValueFactory valueFactory = session.getValueFactory();
Value groupNameValue = valueFactory.createValue(groupName, PropertyType.STRING);
group.setProperty("./profile/givenName", groupNameValue);
session.save();
log.info("---> {} Group successfully created.", group.getID());
} else {
log.info("---> Group already exist..");
}
// Create a User
User user = null;
if (userManager.getAuthorizable(userName) == null) {
user = userManager.createUser(userName, password);
ValueFactory valueFactory = session.getValueFactory();
Value firstNameValue = valueFactory.createValue("Arpit", PropertyType.STRING);
user.setProperty("./profile/givenName", firstNameValue);
Value lastNameValue = valueFactory.createValue("Bora", PropertyType.STRING);
user.setProperty("./profile/familyName", lastNameValue);
Value emailValue = valueFactory.createValue("arpit.p.bora#gmail.com", PropertyType.STRING);
user.setProperty("./profile/email", emailValue);
session.save();
// Add User to Group
Group addUserToGroup = (Group) (userManager.getAuthorizable(groupName));
addUserToGroup.addMember(userManager.getAuthorizable(userName));
session.save();
// set Resource-based ACLs
String nodePath = user.getPath();
setAclPrivileges(nodePath, session);
log.info("---> {} User successfully created and added into group.", user.getID());
} else {
log.info("---> User already exist..");
}
} catch (Exception e) {
log.info("---> Not able to perform User Management..");
log.info("---> Exception.." + e.getMessage());
} finally {
if (session != null && session.isLive()) {
session.logout();
}
if (resourceResolver != null)
resourceResolver.close();
}
}
public static void setAclPrivileges(String path, Session session) {
try {
AccessControlManager aMgr = session.getAccessControlManager();
// create a privilege set
Privilege[] privileges = new Privilege[] {
aMgr.privilegeFromName(Privilege.JCR_VERSION_MANAGEMENT),
aMgr.privilegeFromName(Privilege.JCR_MODIFY_PROPERTIES),
aMgr.privilegeFromName(Privilege.JCR_ADD_CHILD_NODES),
aMgr.privilegeFromName(Privilege.JCR_LOCK_MANAGEMENT),
aMgr.privilegeFromName(Privilege.JCR_NODE_TYPE_MANAGEMENT),
aMgr.privilegeFromName(Replicator.REPLICATE_PRIVILEGE) };
AccessControlList acl;
try {
// get first applicable policy (for nodes w/o a policy)
acl = (AccessControlList) aMgr.getApplicablePolicies(path).nextAccessControlPolicy();
} catch (NoSuchElementException e) {
// else node already has a policy, get that one
acl = (AccessControlList) aMgr.getPolicies(path)[0];
}
// remove all existing entries
for (AccessControlEntry e : acl.getAccessControlEntries()) {
acl.removeAccessControlEntry(e);
}
// add a new one for the special "everyone" principal
acl.addAccessControlEntry(EveryonePrincipal.getInstance(), privileges);
// the policy must be re-set
aMgr.setPolicy(path, acl);
// and the session must be saved for the changes to be applied
session.save();
} catch (Exception e) {
log.info("---> Not able to perform ACL Privileges..");
log.info("---> Exception.." + e.getMessage());
}
}
In code "datawrite" is a service mapping which is mapped with system user in "Apache Sling Service User Mapper Service" which is configurable in the OSGI configuration admin interface.
For more detail about system user check link - How to Create System User in AEM?
I am providing this code direcly from a training of an official Adobe channel, and it is based on AEM 6.1. So I assume this might be the best practice.
private void modifyPermissions() {
Session adminSession = null;
try{
adminSession = repository.loginService(null, repository.getDefaultWorkspace());
UserManager userMgr= ((org.apache.jackrabbit.api.JackrabbitSession)adminSession).getUserManager();
AccessControlManager accessControlManager = adminSession.getAccessControlManager();
Authorizable denyAccess = userMgr.getAuthorizable("deny-access");
AccessControlPolicyIterator policyIterator =
accessControlManager.getApplicablePolicies(CONTENT_GEOMETRIXX_FR);
AccessControlList acl;
try{
acl=(JackrabbitAccessControlList) policyIterator.nextAccessControlPolicy();
}catch(NoSuchElementException nse){
acl=(JackrabbitAccessControlList) accessControlManager.getPolicies(CONTENT_GEOMETRIXX_FR)[0];
}
Privilege[] privileges = {accessControlManager.privilegeFromName(Privilege.JCR_READ)};
acl.addAccessControlEntry(denyAccess.getPrincipal(), privileges);
accessControlManager.setPolicy(CONTENT_GEOMETRIXX_FR, acl);
adminSession.save();
}catch (RepositoryException e){
LOGGER.error("**************************Repo Exception", e);
}finally{
if (adminSession != null)
adminSession.logout();
}

Programatically Give Group Permission in AEM?

i need to give group permission in AEM by use programatically instead of ALL i need only give permission [Replicate] and [Edit] and [Create]
My Codes Here :-
privileges = new Privilege[] {accCtrlMgr.privilegeFromName(Privilege.JCR_ALL)};
Instead of [ Privilege.JCR_ALL ] i want only [Replicate] and [Edit] and [Create]
I hope this code is helpful.
public static void setCreateEditReplicateAcl(final String aGroupPrincipal, String aPath, final UserManagementService aUserManagementService, final Session aSession) {
try {
UserManager userManager = aUserManagementService.getUserManager(aSession);
AccessControlManager accessControlManager = aSession.getAccessControlManager();
Authorizable group = userManager.getAuthorizable(aGroupPrincipal);
Privilege[] privileges = {
accessControlManager.privilegeFromName(Privilege.JCR_VERSION_MANAGEMENT),
accessControlManager.privilegeFromName(Privilege.JCR_MODIFY_PROPERTIES),
accessControlManager.privilegeFromName(Privilege.JCR_ADD_CHILD_NODES),
accessControlManager.privilegeFromName(Privilege.JCR_LOCK_MANAGEMENT),
accessControlManager.privilegeFromName(Privilege.JCR_NODE_TYPE_MANAGEMENT),
accessControlManager.privilegeFromName(Replicator.REPLICATE_PRIVILEGE)
};
AccessControlList aclList;
try {
aclList = (AccessControlList) accessControlManager.getApplicablePolicies(aPath).nextAccessControlPolicy();
} catch (NoSuchElementException e) {
aclList = (AccessControlList) accessControlManager.getPolicies(aPath)[0];
}
aclList.addAccessControlEntry(group.getPrincipal(), privileges);
accessControlManager.setPolicy(aPath, aclList);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
If you are setting the acl with the ui, it creates the following privileges:
jcr:versionManagement, jcr:modifyProperties, jcr:addChildNodes, crx:replicate, jcr:lockManagement, jcr:nodeTypeManagement
I think this are the privileges you need.
The JCR API package javax.jcr.security covers the authorization part, ie. what a certain user is allowed to do with the repository, but not UserManagement, which is provided by Jackrabbit as an implementation-specific feature.
Below is the code sample for giving Resource-based ACLs to a specific node/path:
public static void setAclPrivileges(String path, Session session) {
try {
AccessControlManager aMgr = session.getAccessControlManager();
// create privilege set
Privilege[] privileges = new Privilege[] {
aMgr.privilegeFromName(Privilege.JCR_VERSION_MANAGEMENT),
aMgr.privilegeFromName(Privilege.JCR_MODIFY_PROPERTIES),
aMgr.privilegeFromName(Privilege.JCR_ADD_CHILD_NODES),
aMgr.privilegeFromName(Privilege.JCR_LOCK_MANAGEMENT),
aMgr.privilegeFromName(Privilege.JCR_NODE_TYPE_MANAGEMENT),
aMgr.privilegeFromName(Replicator.REPLICATE_PRIVILEGE) };
AccessControlList acl;
try {
// get first applicable policy (for nodes w/o a policy)
acl = (AccessControlList) aMgr.getApplicablePolicies(path).nextAccessControlPolicy();
} catch (NoSuchElementException e) {
// else node already has a policy, get that one
acl = (AccessControlList) aMgr.getPolicies(path)[0];
}
// remove all existing entries
for (AccessControlEntry e : acl.getAccessControlEntries()) {
acl.removeAccessControlEntry(e);
}
// add a new one for the special "everyone" principal
acl.addAccessControlEntry(EveryonePrincipal.getInstance(), privileges);
// the policy must be re-set
aMgr.setPolicy(path, acl);
// and the session must be saved for the changes to be applied
session.save();
} catch (Exception e) {
log.info("---> Not able to perform ACL Privileges..");
log.info("---> Exception.." + e.getMessage());
}
}
Check Apache Jackrabbit AccessControl for more details.

Play framework and ionic for mobile I need Security without cookies but token

I have an issue with using mobile app that I created in Ionic and back-end APIs that I coded in play framework, my issue simply is I need way to handle security matter for calling APIs that need to be secured, mean user must be logged in to do actions, as example guest can view group but can join only if logged in.
My issue that I believe that cookies is not supported for Mobile, i have code checking session that stored in cookies, its working for website, but it will not work for mobile, right?
Currently I'm trying to send a token that generated in back-end and returned with login response and stored in localStorage in Ionic, but my issue is that I can't sent token to be validated with request.
Front End:
I have the following http interceptor :
angular
.module('app.core')
.factory('sessionInjector', sessionInjector);
/** #ngInject */
function sessionInjector($q, sessionService, $rootScope) {
return {
request: function (config) {
$rootScope.$broadcast('loading:show');
if (!sessionService.isAnonymous())
config.headers['x-session-token'] = sessionService.getToken();
}
return config;
}
}
Back-End:
Controller:
#Security.Authenticated(Secure.class)
public Result joinOrganization() {
// Do some business
}
Secure.java :
#Override
public String getUsername(Http.Context ctx) {
// Is this correct way? I get null here
String str = ctx.request().getHeader("x-session-token");
String userId = ctx.session().get("usedId");
if (userId == null) {
return null;
}
User user = Play.application().injector().instanceOf(UserService.class).findUserById(Integer.parseInt(userId));
if (user != null && user.isActive) {
return user.id;
} else {
return null;
}
}
#Override
public Result onUnauthorized(Http.Context ctx) {
return unauthorized(results);
}
Note: Tokens stored in database:
Entity:
#Entity
#Table(name = "AUTHTOKEN")
public class AuthToken extends BaseModel {
#OneToOne(targetEntity = User.class, cascade = CascadeType.REFRESH, optional = false)
public User user;
#Column(nullable = false)
public String token;
#Column
public long expiration;
public AuthToken() {
}
}
For cookies working, but need to remove cookies and use tokens, or use them together cookies for website, tokens for mobile .
Mobile is no different to otherwise in regards of cookies. There are restrictions if AJAX, or cross-domain requests are used, and specially with Apple stuff, but they apply to non-mobile too. If your cookies work on a PC/Mac, they should do on a mobile device just as well. It's more of a form factor than anything else...
I found solution and it was complicated because there are many issues starting from that ngResource does not apply request interceptor its an issue opened from long time.
Second issue was how to send the token with ngResource, its simply with adding headers, the another issue here is getting dynamically the token, this "dynamically" means because the localStorage in memory getting lost when refresh so you need to get back it, this can be done with service, and function call for getting the token, something like this :
$resource('/user/:userId/card/:cardId', {userId:123, cardId:'#id'}, {
charge: {method:'POST', params:{charge:true}, headers = {
'x-session-token': function () {
return sessionService.getToken()
}}
});
Inside sessionService :
// this to recreate the cache in memory once the user refresh, it will keep the data if exisit but will point to it again in memory
if (CacheFactory.get('profileCache') == undefined) {
//if there is no cache already then create new one and assign it to profileCache
CacheFactory.createCache('profileCache');
}
function getCurrentSession() {
var profileCache = CacheFactory.get('profileCache');
if (profileCache !== undefined && profileCache.get('Token') !== undefined) {
return profileCache.get('Token');
}
return null;
}
function getToken() {
var currentSession = getCurrentSession();
if (currentSession != null && currentSession != '') {
return currentSession.token;
}
return null;
}
And then this method will work inside Secure.java
protected User getUser(Http.Context ctx) {
String token = ctx.request().getHeader("x-session-token");
if (token != null) {
return securityService.validateToken(token);
}
return null;
}

Grails Spock - throwing an exception from a service UndeclaredThrowableException

In runtime this code works:
// Service class
class UserService {
ApiClient api
User create(User user) throws EmailTakenException, UsernameTakenException {
User savedUser
try {
savedUser = api.users.create user
setEnabled savedUser.id, true
return savedUser
}
catch(ApiException ex) {
switch(ex.subStatus) {
case SubStatus.USERS_EMAIL_TAKEN:
throw new EmailTakenException()
break
case SubStatus.USERS_USERNAME_TAKEN:
throw new UsernameTakenException()
break
}
}
}
}
called from a controller:
// Controller class, an action
def create(CreateCommand cmd) {
if(request.get) {
render view: 'create'
return
}
if(!cmd.validate()) {
flash.model = cmd
redirect action: 'create'
return
}
def user = new User()
bindData user, params
try {
userService.create user
flash.success = 'ui.save.success'
}
catch(EmailTakenException ex) {
flash.model = cmd
flash.error = 'ui.email.taken'
}
catch(UsernameTakenException ex) {
flash.model = cmd
flash.error = 'ui.username.taken'
}
redirect action: 'create'
}
The "User", "SubStatus", and "ApiException" class comes from a jar library dependency. The ApiClient throws an ApiException when something goes wrong.
In runtime this code works perfectly, but when I write a Spec for this, it throws an UndeclaredThrowableException. Here's the Spock Specification:
ApiClient api
UsersApi apiUsers
void setup() {
api = Mock()
apiUsers = Mock()
api.users >> apiUsers
service.api = api
}
def "create: it should be able to throw an exception when email is already taken"() {
setup:
def user = new User(email: 'foo#cod.com', username: 'foo', name: 'Bar Foo')
def exception = Mock(ApiException)
exception.subStatus >> SubStatus.USERS_EMAIL_TAKEN
when:
service.create user
then:
thrown(EmailTakenException) // GrailsException is runtime
1 * apiUsers.create(_ as User) >> { throw new ApiException(400, SubStatus.USERS_EMAIL_TAKEN, null) }
}
Maybe you could rewrite your test using the #FailsWith annotation?
http://code.google.com/p/spock/wiki/SpockBasics#Extensions

Categories