Skip to content

Commit

Permalink
Basic JPA modeling and basic services
Browse files Browse the repository at this point in the history
  • Loading branch information
jpkrohling committed Feb 5, 2015
1 parent fd7f3e4 commit e05e5ff
Show file tree
Hide file tree
Showing 15 changed files with 861 additions and 0 deletions.
25 changes: 25 additions & 0 deletions backend/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,31 @@
<artifactId>hibernate-jpamodelgen</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
* Copyright 2015 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.hawkular.accounts.backend.boundary;

import javax.ejb.Stateless;
import javax.inject.Inject;
import org.hawkular.accounts.backend.entity.HawkularUser;
import org.hawkular.accounts.backend.entity.Organization;
import org.hawkular.accounts.backend.entity.Owner;
import org.keycloak.KeycloakPrincipal;

/**
*
* @author Juraci Paixão Kröhling <juraci at kroehling.de>
*/
@Stateless
public class PermissionChecker {

@Inject
UserService userService;

/**
* Determines whether the current {@link HawkularUser} has access to the resource owned by {@link Owner}
*
* @param currentUser the user to be checked
* @param owner the owner of the resource
* @return true if the user is the owner or if the user belongs to an organization that owns the resource
*/
public boolean hasAccessTo(HawkularUser currentUser, Owner owner) {
if (currentUser.equals(owner)) {
return true;
}

// users don't belong to users, so, if the owner is an user and is not the current user, then it doesn't
// have access
if (owner instanceof HawkularUser) {
return false;
}

return isMemberOf(currentUser, (Organization) owner);
}

/**
* Determines whether the current {@link KeycloakPrincipal} has access to the resources owned by {@link Owner}.
*
* @param principal the {@link KeycloakPrincipal} representing the current user
* @param owner the owner of the resource
* @return true if the user is the owner or if the user belongs to an organization that owns the resource
* @see PermissionChecker#hasAccessTo(
* org.hawkular.accounts.backend.entity.User, org.hawkular.accounts.backend.entity.Owner)
*/
public boolean hasAccessTo(KeycloakPrincipal principal, Owner owner) {
// Here's a bit of explanation: judging by the name of this class, we wouldn't expect any record to be created.
// But in fact, the user *already* exists, just not in our database. So, on the first call of this method for
// a new user, we create it on our side, using Keycloak's ID for this user.
HawkularUser user = userService.getOrCreateById(principal.getName());
return hasAccessTo(user, owner);
}

/**
* Recursively checks whether an user is a member or owner of an organization. Examples:
*
* jdoe is owner of acme -> true
* jdoe is member of acme -> true
* jdoe is member of emca which is member of acme -> true
* emca is member of acme -> true
*
* @param member the member to be checked
* @param organization the organization that might contain the user
* @return true if the user belongs to the organization recursively
*/
public boolean isMemberOf(Owner member, Organization organization) {
// simplest case first: is the member a direct member of this organization?
// example: jsmith is a member of acme
if (organization.getMembers().contains(member)) {
return true;
}

// if the member is the owner of the current organization (or any organization that owns the current organization)
// then he's directly or indirectly owner of the current organization, therefore, he's member of it
// example: jdoe is the owner of acme, acme is owner of emca, therefore, jdoe is the owner of emca
if (isOwnerOf(member, organization)) {
return true;
}

// if the "member" is part of an organization that owns the current organization, then it's a member of it
// example: jsmith is part of acme, acme is owner of emca, therefore, jsmith is member of emca.
Owner organizationOwner = organization.getOwner();
if (organizationOwner instanceof Organization) {
if (isMemberOf(member, (Organization) organizationOwner)) {
return true;
}
}

// if the member is part of a child organization, then it's a member of this one
// example: jdoe is member of emca, emca is member of acme, therefore, jdoe is member of acme
for (Owner organizationMember : organization.getMembers()) {
if (organizationMember instanceof Organization) {
return isMemberOf(member, (Organization) organizationMember);
}
}

return false;
}

/**
* Recursively checks if the specified owner is a direct or indirect owner of the given organization. For instance,
* if jdoe is the owner of acme, and acme owns emca, then jdoe owns emca indirectly.
*
* @param owner the {@link Owner} to check. In our example above, it would be jdoe or acme.
* @param organization the {@link Organization} to verify ownership of. In our example above, it would be emca.
* @return whether or not the specified owner is directly or indirectly the owner of the given organization.
*/
public boolean isOwnerOf(Owner owner, Organization organization) {

if (organization.getOwner().equals(owner)) {
return true;
}

Owner organizationOwner = organization.getOwner();
if (organizationOwner instanceof Organization) {
return isOwnerOf(owner, (Organization) organizationOwner);
}

return false;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright 2015 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.hawkular.accounts.backend.boundary;

import java.util.List;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.hawkular.accounts.backend.entity.HawkularUser;
import org.hawkular.accounts.backend.entity.HawkularUser_;

/**
*
* @author Juraci Paixão Kröhling <juraci at kroehling.de>
*/
@Stateless
public class UserService {

@Inject
EntityManager em;

/**
* Retrieves an {@link HawkularUser} based in its ID
* @param id the user ID
* @return the existing user with the given ID or null if the user is not found.
*/
public HawkularUser getById(String id) {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<HawkularUser> query = builder.createQuery(HawkularUser.class);
Root<HawkularUser> root = query.from(HawkularUser.class);
query.select(root);
query.where(builder.equal(root.get(HawkularUser_.id), id));

List<HawkularUser> results = em.createQuery(query).getResultList();
if (results.size() == 1) {
return results.get(0);
}

if (results.size() > 1) {
throw new IllegalStateException("More than one user found for ID " + id);
}

return null;
}

/**
* Retrieves an {@link HawkularUser} based on its ID. If no user is found, a new one is created and returned.
* @param id the user ID
* @return an {@link HawkularUser} instance representing the user with the given ID. It's never null.
*/
public HawkularUser getOrCreateById(String id) {
HawkularUser user = getById(id);
if (null == user) {
user = new HawkularUser(id);
em.persist(user);
}

return user;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 2015 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.hawkular.accounts.backend.control;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import javax.persistence.PersistenceContext;

/**
*
* @author Juraci Paixão Kröhling <juraci at kroehling.de>
*/
@ApplicationScoped
public class ApplicationResources {
@Produces
@PersistenceContext
private static javax.persistence.EntityManager em;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 2015 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.hawkular.accounts.backend.control;

import org.jboss.logging.Logger;
import org.jboss.logging.annotations.MessageLogger;
import org.jboss.logging.annotations.ValidIdRange;

/**
*
* @author Juraci Paixão Kröhling <juraci at kroehling.de>
*/
@MessageLogger(projectCode = "HAWKACC")
@ValidIdRange(min = 100000, max = 109999)
public interface HawkularAccountsMessageLogger {
HawkularAccountsMessageLogger LOGGER = Logger.getMessageLogger
(HawkularAccountsMessageLogger.class, HawkularAccountsMessageLogger.class.getPackage().getName());

}
Loading

0 comments on commit e05e5ff

Please sign in to comment.