How create apache shiro authorization with JPA? - java

I change shiro auth from native SQL to JPA and I have some quations.
I make for example this link and this link
but i have errors.
[2015-12-03 08:58:33,087] Artifact ear:ear exploded: Artifact is being deployed, please wait...
[2015-12-03 08:59:06,931] Artifact ear:ear exploded: Error during artifact deployment. See server log for details.
[2015-12-03 08:59:06,932] Artifact ear:ear exploded: java.io.IOException: com.sun.enterprise.admin.remote.RemoteFailureException: Error occurred during deployment: Exception while loading the app : java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: java.lang.NoClassDefFoundError: org/apache/commons/collections/FastHashMap. Please see server.log for more details.
I not understend how it work. I Create JpaAuthorizingRealm class:
public class JpaAuthorizingRealm extends AuthorizingRealm {
public static final String REALM_NAME = "MY_REALM";
public static final int HASH_ITERATIONS = 200;
#Override
protected AuthorizationInfo doGetAuthorizationInfo(final PrincipalCollection principals) {
Long userId = (Long) principals.fromRealm(getName()).iterator().next();
User user = ShiroDao.me().userById(userId);
if (user != null) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
for (Role role : user.getRoles()) {
info.addRole(role.getRoleName());
for (Permission permition : user.getPermissions()) {
info.addStringPermission(permition.getPermission());
}
}
return info;
} else {
return null;
}
}
#Override
protected AuthenticationInfo doGetAuthenticationInfo(final AuthenticationToken authToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authToken;
User user = ShiroDao.me().userByname(token.getUsername());
if (user != null) {
return new SimpleAuthenticationInfo(user.getId(), user.getPassword(), getName());
} else {
return null;
}
}
#Override
#Inject
public void setCredentialsMatcher(final CredentialsMatcher credentialsMatcher) {
super.setCredentialsMatcher(credentialsMatcher);
}
}
And models User, Role and Permission. And in ini file i registered :
[main]
cacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
securityManager.cacheManager = $cacheManager
# realms to be used
adRealm = myPackeg.CustomActiveDirectoryRealm
adRealm.url = ldap://myIP
noPassWordCredentialMatcher=myPackeg.CustomNoPassMatcher
userRealm=myPackeg.JpaAuthorizingRealm
userRealm.permissionsLookupEnabled=true
userRealm.credentialsMatcher=$noPassWordCredentialMatcher
authc.loginUrl = /login.xhtml
user.loginUrl = /login.xhtml
authc.successUrl = /index.xhtml?faces-redirect=true
roles.unauthorizedUrl = /error/ErrorInsufficientPrivileges.xhtml?faces-redirect=true
securityManager.realms= $adRealm, $customSecurityRealm
authcStrategy = org.apache.shiro.authc.pam.AllSuccessfulStrategy
securityManager.authenticator.authenticationStrategy = $authcStrategy
;multipleroles = myPackeg.MultipleRolesAuthorizationFilter
multipleroles = myPackeg.MultipleRolesAuthorizationFilter
[roles]
[urls]
/javax.faces.resource/** = anon
/error/ = anon
/login.xhtml = authc
/logout = logout
#/admin/ChangePassword.xhtml= authc, roles[user]
/admin/**= authc, roles[administrator]
/reports/qcforcc_report.xhtml= authc, roles[user]
/reports/**= authc, roles[administrator]
/** = authc, roles[user]
#/** = user, multipleroles["administrator", "user"]
And if i change JpaAuthorizingRealm extends AuthorizingRealm to JpaAuthorizingRealm extends JdbcRealm error not shows.
Maby somebode know how create shiro auth with JPA?

This seems to more like a linkage error than a problem with Shiro. The error means that your code (or code in Shiro library) cannot find FastHashMap class from commons-collections.
This is most probably because have more than a single version of commons-collections in your classpath (your application, app server, etc.). The problem might be that an older version of commons-collections is getting preference before the newer version, and that the older version does not include FastHashMap.

I have implemented shiro with jpa and you can find the source code at https://github.com/nmojir/rest-basic-auth.

Related

Retrieve all Managed Devices using Java (with Microsoft Graph API SDK)

I would like to retrieve all devices managed by Intune (managed devices) using the Microsoft Graph Java SDK. I have created the app in Microsoft Azure and given the appropriate API permissions:
API Permissions
The following code creates a graphClient object and a method that retrieves all managed devices.
#Service
public class AzureServiceDefault implements AzureService
{
private static final String CLIENT_ID = "XXXXXXXXXXXXXXXXXXXXXXXX";
private static final List<String> SCOPES = Arrays.asList(new String[]{"https://graph.microsoft.com/.default"});
private static final String TENANT = "XXXXXXXXXXXXXXXXXXXXXXXX";
private static final String CLIENT_SECRET = "XXXXXXXXXXXXXXXXXXXXXXXX";
ClientCredentialProvider authProvider = new ClientCredentialProvider(CLIENT_ID, SCOPES, CLIENT_SECRET, TENANT, NationalCloud.Global);
IGraphServiceClient graphClient;
public AzureServiceDefault()
{
graphClient = GraphServiceClient.builder().authenticationProvider(authProvider).buildClient();
}
#Override
public List<IntuneDevice> getManagedDevices()
{
IManagedDeviceCollectionRequestBuilder managedDeviceRequestBuilder;
IDeviceManagementRequestBuilder builder = graphClient.deviceManagement();
IDeviceManagementRequest managedDevicesRequest = builder.buildRequest();
List<ManagedDevice> managedDevices = new ArrayList<>();
List<IntuneDevice> allManagedDevices = new ArrayList<>();
do {
try {
DeviceManagement deviceManagement = managedDevicesRequest.get();
ManagedDeviceCollectionPage managedDevicesCollectionPage = deviceManagement.managedDevices;
//Process items in the response
managedDevices.addAll(managedDevicesCollectionPage.getCurrentPage());
managedDevices.stream().forEach((device) -> allManagedDevices.add(new IntuneDevice(device.id,
device.userId,
device.deviceName,
device.managedDeviceOwnerType.toString(),
device.operatingSystem,
device.osVersion,
device.complianceState.toString(),
device.azureADRegistered,
device.azureADDeviceId,
device.userPrincipalName,
device.model,
device.manufacturer,
device.serialNumber)));
//Build the request for the next page, if there is one
managedDeviceRequestBuilder = managedDevicesCollectionPage.getNextPage();
if (managedDeviceRequestBuilder == null)
{
managedDevicesRequest = null;
}
else
{
managedDevicesRequest = (IDeviceManagementRequest) managedDeviceRequestBuilder.buildRequest();
}
}
catch(ClientException ex)
{
ex.printStackTrace();
managedDevicesRequest = null;
}
} while (managedDevicesRequest != null);
return allManagedDevices;
}
}
The problem is that the variable managedDevices turns out to be null and this is the error message:
SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/] threw exception [Request processing failed; nested exception is java.lang.NullPointerException: Cannot invoke "com.microsoft.graph.requests.extensions.ManagedDeviceCollectionPage.getCurrentPage()" because "managedDevicesCollectionPage" is null] with root cause
java.lang.NullPointerException: Cannot invoke "com.microsoft.graph.requests.extensions.ManagedDeviceCollectionPage.getCurrentPage()" because "managedDevicesCollectionPage" is null
What do I need to change to make this code work? I am succesfully able to retrieve all users in Azure AD, but I am having difficulties getting data from Intune/Endpoint Manager. Do I need to make changes to the SCOPES?
It should be possible to retrieve all managed devices as the REST API for it is https://graph.microsoft.com/v1.0/deviceManagement/managedDevices
Thanks for your help
This MS Graph API does not support application permissions, so you couldn't list managedDevices with ClientCredentialProvider. ClientCredentialProvider is based on client credential flow that requires application permission.
You could use AuthorizationCodeProvider to get the list. And follow this to get AUTHORIZATION_CODE first.
String CLIENT_ID = "xxxxxx";
List<String> SCOPES = Arrays.asList(new String[] { "https://graph.microsoft.com/.default" });
String CLIENT_SECRET = "xxxxxx";
String TENANT = "xxxxxx";
String AUTHORIZATION_CODE = "";
String REDIRECT_URL = "xxxxxx";
AuthorizationCodeProvider authProvider = new AuthorizationCodeProvider(CLIENT_ID, SCOPES, AUTHORIZATION_CODE,
REDIRECT_URL, NationalCloud.Global, TENANT, CLIENT_SECRET);
IGraphServiceClient graphClient = GraphServiceClient.builder().authenticationProvider(authProvider).buildClient();
IManagedDeviceCollectionPage managedDeviceCollectionPage = graphClient.deviceManagement().managedDevices().buildRequest().get();
List<ManagedDevice> managedDeviceList = managedDeviceCollectionPage.getCurrentPage();

Getting Cognito Credentials on Android

I need to authenticate a user using AWS's Cognito in Android and get a token to use on my future requests. Some information is provided to me by the backend but I still haven't managed to use it in the appropriate way, and Cognito's documentation did not help me on this. I have this fixed info:
Pool Region: us-east-1
Pool ID: us-east-1:xxxxx-xxxxx-xxxxx-xxxx-xxxxxxxx
And after authenticating the user on the login endpoint I get this info:
{
"cognitoId": "us-east-1:yyyy-yyyy-yyyy-yyyy-yyyyyyy",
"cognitoToken": "hH1Q8bCLh9-pamP6DCrC0-KY4rNtZ115xDedE224CeEanex-CCWh4tWUtJjPc_tU3d6eJ_7Uk23ceTNhCFYT1qnAL_7kAH_lHod4a1GQo29FuTLQSqx4lOFv2Ev3RvYcCzjyLEAA1-EIKBtfSm_YN9y6DHBOzDJ8owLJTxB0JEWvsWfATjug4P8hxCI97RVB2cetrmq4JvZr__bCziUb-7AifPvy4VMW3xLjJ7uyDvogwcx5gJ1rF8Z38_z7kREB1R_CYPRVQuoHzag0j9RoOTNeAYFGO42qgCewTl3Lvm5PUbTIGhCIp6y1RVWAPLEdMWmQ3LVpqJcZKLQRhMmEzOGMyTUiXSwiaXNzIjoiaHR0cHM6Ly9jb2duaXRvLWlkZW50aXR5LmFtYXpvbmF3cy5jb20iLCJleHAiOjE1MTE2NDEzMDksImlhdCI6MTUxMTYyNjkwOX0.QFWGxh_"
}
The IDs were omitted and the token was altered in order to preserve the information. It is important to note that the Pool ID (constant in the app) and the cognitoId (returned by the backend) are different.
I have a static Credentials Provider initialized like this:
credentialsProvider = new CognitoCachingCredentialsProvider(
getApplicationContext(), /* get the context for the application */
IDENTITY_POOL_ID, /* Identity Pool ID */
Regions.US_EAST_1 /* Region for your identity pool--US_EAST_1 or EU_WEST_1*/
);
This is the task that does the work of trying to get the Cognito auth:
private static final class CognitoAuthTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... strings) {
String userId = strings[0];
String token = strings[1];
String sessionToken = null;
try {
Map<String, String> logins = new HashMap<String, String>();
logins.put(userId, token);
credentialsProvider.setLogins(logins);
AWSSessionCredentials credentials = credentialsProvider.getCredentials();
sessionToken = credentials.getSessionToken();
} catch (Exception e) {
if (BuildConfig.DEBUG) {
e.printStackTrace();
}
} finally {
return sessionToken;
}
}
#Override
protected void onPostExecute(String authToken) {
super.onPostExecute(authToken);
cognitoAuthToken = authToken;
if (BuildConfig.DEBUG) {
Log.d("Cognito Token", cognitoAuthToken == null ? "null" : cognitoAuthToken);
}
}
}
And this is where I call it when I have the information from my login endpoint (as I showed above):
public void authenticateCognito(String userId, String token) {
new CognitoAuthTask().execute(userId, token);
}
The problem is that this is not working, I get this error here:
Invalid login token. Can't pass in a Cognito token. (Service:
AmazonCognitoIdentity; Status Code: 400; Error Code:
NotAuthorizedException; Request ID: zzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzz)
The error happens on the task, on this line of code here:
credentialsProvider.getCredentials();
The backend team mentioned that I would need to use the GetCredentialsForIdentity method, but I can't find anything like that on the Cognito Android SDK.
Any help is appreciated.
The class you should be using is AmazonCognitoIdentityClient, that is the class implementing the GetCredentialsForIdentity API.
When credentialsProvider.getCredentials(); is invoked, the internal AmazonCognitoIdentityClient calls GetCredentialsForIdentity to get new credentials from Cognito.
The Invalid login token error is returned by the service if the provided token has expired.

Using Google authentication with Restlet

I have this very basic authentication for my app:
MapVerifier mapVerifier = new MapVerifier();
mapVerifier.getLocalSecrets().put("user", "pass".toCharArray());
ChallengeAuthenticator guard= new ChallengeAuthenticator(null, ChallengeScheme.HTTP_BASIC, "Secured Resources");
guard.setContext(getContext());
guard.setVerifier(mapVerifier);
How do I adapt this to use Google authentication scheme? That, instead of showing the Username/Password browser popup, it will go to the Google authentication page.
I think that you aren't in the context of a challenge authentication and you need to leverage the authentication service of Google.
Here is an implementation of this approach (not tested) if you want a custom Restlet Authenticator implementation:
public class GoogleAuthenticator extends Authenticator {
private UserService userService;
public GoogleAuthenticator(Context context) {
super(context);
this.userService = UserServiceFactory.getUserService();
}
protected User createUser(com.google.appengine.api.users.User googleUser,
Request request, Response response) {
return new User(googleUser.getUserId());
}
protected boolean authenticate(Request request, Response response) {
// Get current Google user
com.google.appengine.api.users.User googleUser = userService.getCurrentUser();
// Check if the user is authenticated
if (googleUser!=null) {
// Authenticated through Google authentication service
request.getClientInfo().setUser(
createUser(googleUser, request, response));
return true;
} else {
// Not authenticated. Redirect to the login URL
response.redirectSeeOther(userService.createLoginURL(
request.getRequestURI()));
return false;
}
}
}
However such authenticator exists in the extension org.restlet.ext.gae for a while. It leverages the service UserService of GAE. So I think that you have it with the version of Restlet you use. Here is a sample of use below:
public Restlet createInboundRoot() {
Router router = new Router(getContext());
(...)
GaeAuthenticator guard= new GaeAuthenticator(getContext());
guard.setNext(router);
return guard;
}
Edited:
You can notice that the GAE authenticator can use the GAE enroler for this purpose (i.e. if it's an admin one).
To implement this, you simply need to instantiate such enroler and set it on your authenticator, as desribed below:
GaeEnroler enroler = new GaeEnroler();
GaeAuthenticator guard = new GaeAuthenticator(getContext());
guard.setEnroler(enroler)
guard.setNext(router);
Within your server resource, you can then check the role, as described below:
protected boolean hasAdminRole() {
ClientInfo clientInfo = getClientInfo();
List<Role> roles = clientInfo.getRoles();
boolean isAdmin = false;
for (Role role : roles) {
if (role.getName().equals("admin")) {
isAdmin = true;
break;
}
}
return isAdmin;
}
#Post
public XX handlePost(YY content) {
if (!hasAdminRole()) {
throw new ResourceException(Status.CLIENT_ERROR_FORBIDDEN);
}
(...)
}
Hope it helps you,
Thierry
I haven't fully understood what's ur question is ? If u wanted to integrate Google authentication in yours system check the link
google Oauth2
It's not depend upon any framework it's simply redirection and callback which u can do with plain servlets , obviously you can do with restlets too
I have written an simply library to integrate google and Facebook oauth 2, you can check this to see how it works
java oauth2 gae

getting exception Authentication failed for token submission in apache shiro

i am new in apache shiro.i am getting exception when i execute this statement.
currentUser.login(token);
exception is
errororg.apache.shiro.authc.AuthenticationException: Authentication failed for token submission [org.apache.shiro.authc.UsernamePasswordToken - abc#gmail.com, rememberMe=true]. Possible unexpected error? (Typical or expected login exceptions should extend from AuthenticationException).
i am invoking this method for login.the code is.
public boolean authorize(String username,String password)
{
Boolean status=false;
log.debug("the user id "+username+"passwrodD::"+password);
Realm realm = new JdbcRealm();
DefaultSecurityManager securityManager = new DefaultSecurityManager(realm);
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
token.setRememberMe(true);
SecurityUtils.setSecurityManager(securityManager);
Subject currentUser = SecurityUtils.getSubject();
Response r = null;
log.debug("before process for login");
try
{
currentUser.login(token); //This throws an error upon form submission
r = Response.ok().entity(token).build();
}
catch (UnknownAccountException uae ) {
//username wasn't in the system, show them an error message?
System.out.println("the user name is invalid");
} catch ( IncorrectCredentialsException ice ) {
//password didn't match, try again?
System.out.println("the password name is invalid");
} catch ( LockedAccountException lae ) {
//account for that username is locked - can't login. Show them a message?
} catch ( AuthenticationException ae ) {
//unexpected condition - error?
System.out.println("unexpect error"+ae);
}
return status;
}
my shiro.ini file
[main]
jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.permissionsLookupEnabled = true
jdbcRealm.authenticationQuery =select User_Password FROM user_master where User_id=?
ds = com.mysql.jdbc.jdbc2.optional.MysqlDataSource
ds.serverName = localhost
ds.user = root
ds.password = root
ds.databaseName = test
jdbcRealm.dataSource = $ds
[users]
[roles]
[urls]
i include listener and filter in my web.xml file.
i change the authenticationQuery to my query. and when i am executing i am getting this above error. and also i do know is it right way to modify or override query.
I think the problem is that you are missing securityManager.realm = $jdbcRealm in your shiro.ini
I just got this exception, and the problem was I was setting securityManager.realm incorrectly in shiro.ini. This is what I had:
[main]
fooRealm = com.company.foo.Realm
securityManager.realms = fooRealm
This is what fixed it (I was missing a $):
[main]
fooRealm = com.company.foo.Realm
securityManager.realms = $fooRealm

Auto-creating User details with Grails and LDAP

I'm using the Acegi Security plugin for Grails, and authentication via LDAP.
The application logs show that on login, we can authenticate the user and get their roles via LDAP, but the login fails because the User Details cannot be found in the application's database.
Is there a way to auto create and save a basic User Details domain object if one doesn't already exist?
-- Update
Here are the relevant debug entries I am currently seeing
DEBUG populator.DefaultLdapAuthoritiesPopulator - Roles from search: [Role1, Role2, etc]
ERROR springsecurity.GrailsDaoImpl - User not found: MyUserName
DEBUG rememberme.TokenBasedRememberMeServices - Interactive login attempt was unsuccessful.
Sure.
You need to implement custom AuthProvider
SecurityConfig.groovy:
security {
providerNames = ['ldapAuthProvider']
}
Ldap Auth Provider:
import domain.user.AppUser
import org.apache.commons.codec.digest.DigestUtils
import org.apache.log4j.Logger
import org.codehaus.groovy.grails.plugins.springsecurity.GrailsUserImpl
import org.springframework.security.BadCredentialsException
import org.springframework.security.GrantedAuthority
import org.springframework.security.GrantedAuthorityImpl
import org.springframework.security.providers.UsernamePasswordAuthenticationToken
import org.springframework.security.providers.dao.AbstractUserDetailsAuthenticationProvider
import org.springframework.security.userdetails.UserDetails
/**
* Authentication provider that checks user credentials against LDAP
*/
class LdapAuthProvider extends AbstractUserDetailsAuthenticationProvider {
private static final Logger log = Logger.getLogger(LdapAuthProvider.class)
def appUserService
/**
* Checks password hash stored in the session with password in authentication token.
*/
protected void additionalAuthenticationChecks(UserDetails details,
UsernamePasswordAuthenticationToken authentication) {
if (details.password != DigestUtils.md5Hex(authentication.credentials)) {
throw new BadCredentialsException(details.username)
}
}
/**
* Retrieves user from LDAP,
* checks credentials,
* updates local copy of user data,
* returns user details.
*/
protected UserDetails retrieveUser(String login, UsernamePasswordAuthenticationToken authentication) {
AppUser.withTransaction {
log.debug("Trying to retrieve user \"$login\"...")
def password = authentication.credentials?.toString()
def ldapUser = appUserService.findLdapUser(login)
if (!(password && ldapUser?.authenticate(password))) {
log.debug("Can't authenticate \"$login\"")
throw new BadCredentialsException(login)
}
AppUser localUser = AppUser.findByLogin(login, [cache: true])
if (!localUser) {
log.debug("Can't authenticate \"$login\"")
localUser = appUserService.updateLocalUser(ldapUser)
}
log.debug("User \"$login\" is authenticated.")
def authorities = localUser.collectAuthorities().collect {String authority ->
log.debug("\thas right \"$authority\"")
new GrantedAuthorityImpl(authority)
}
def userDetails = new AppUser();
userDetails.setAssignedTemplate(localUser.assignedTemplate)
userDetails.setFullName(localUser.getFullName())
userDetails.setLogin(localUser.getLogin())
userDetails.setEmail(localUser.getEmail())
userDetails.setDisabled(localUser.getDisabled())
userDetails.setManager(localUser.getManager())
userDetails.setRoles(new HashSet(localUser.getRoles()))
log.debug("Retrieving user \"$login\" is completed.")
return new GrailsUserImpl(userDetails.login, DigestUtils.md5Hex(password), true, true, true, true,
authorities.toArray(new GrantedAuthority[authorities.size()]), userDetails)
}
}
}
And in appUserService.updateLocalUser(ldapUser) you need create/modify your Domain object and persist in database.
AppUser updateLocalUser(LdapUser ldapUser) {
def login = ldapUser.login
log.debug("Start updating local user ${login}...")
def localUser = AppUser.findByLogin(login, [cache: true]) ?: new AppUser()
if (localUser.id) {
log.debug("user $login was found in local DB")
if (localUser.disabled ^ ldapUser.isDisabled()) {
log.debug("...user ${login} has been ${localUser.disabled ? 'activated' : 'disabled'}...")
}
} else {
log.debug("user $login is new")
}
localUser.login = login
localUser.email = ldapUser.email
localUser.fullName = ldapUser.fullName ?: login
localUser.disabled = ldapUser.isDisabled();
localUser.roles?.clear()
ldapUser.memberOf.collect { Role.findByLdapName(it, [cache: true]) }.each {role ->
if (role) {
localUser.addToRoles(role)
}
};
localUser.save(flush: true)
log.debug("Update local user $login is complete.")
}
UPDATE #1
You can implement custom UserDetailsService:
package com.foo.bar;
import org.springframework.security.userdetails.UserDetails; import org.springframework.security.userdetails.UserDetailsService;
public class MyUserDetailsService implements UserDetailsService {
public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException, DataAccessException {
// lookup user and data
return new MyUserDetails(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities, id, fullName); } }

Categories

Resources