restructured code and introduced JWTAuthenticationFilter support to ensure user and roles are loaded when using JWT to sign in

This commit is contained in:
2018-12-14 09:55:32 +01:00
parent 6bad0e75a6
commit 7acc23892b
14 changed files with 1031 additions and 439 deletions

View File

@ -76,6 +76,10 @@
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>

View File

@ -77,13 +77,12 @@ public class AccountProducer implements Serializable {
}
if ((subject.isAuthenticated() == false) && (subject.isRemembered() == false)) {
accountName = "web";
return null;
} else {
accountName = subject.getPrincipal().toString();
}
account = accountController.getAccountEntity(accountName, true);
// TODO introduce locale support to account and switch
// to pre-defined locale if set
// TODO introduce locale support to account and switch to pre-defined locale if set
}
return account;
}

View File

@ -1,11 +1,11 @@
package de.muehlencord.shared.account.business.account.boundary;
import de.muehlencord.shared.account.business.config.boundary.ConfigService;
import de.muehlencord.shared.account.business.account.control.AccountControl;
import de.muehlencord.shared.account.business.account.entity.Account;
import de.muehlencord.shared.account.business.account.entity.AccountEntity;
import de.muehlencord.shared.account.business.account.entity.ApiKeyEntity;
import de.muehlencord.shared.account.business.account.entity.JWTObject;
import de.muehlencord.shared.account.business.config.boundary.ConfigService;
import de.muehlencord.shared.account.business.config.entity.ConfigException;
import de.muehlencord.shared.account.util.AccountPU;
import de.muehlencord.shared.jeeutil.jwt.JWTDecoder;
@ -126,7 +126,7 @@ public class ApiKeyService implements Serializable {
return validKey != null;
}
public ApiKeyEntity getValidKey(String userName, String apiKey, String authorizationHeader) {
private ApiKeyEntity getValidKey(String userName, String apiKey, String authorizationHeader) {
AccountEntity userAccount = accountControl.getAccountEntity(userName, false);
List<ApiKeyEntity> apiKeys = getUsersApiKeys(userAccount);
@ -160,8 +160,8 @@ public class ApiKeyService implements Serializable {
}
}
public JWTObject getJWTObject(String authorizationHeader) {
JWTDecoder decoder = new JWTDecoder(password, issuer, authorizationHeader);
public JWTObject getJWTObject(String encodedJWT) {
JWTDecoder decoder = new JWTDecoder(password, issuer, encodedJWT);
JWTObject jwtObject = new JWTObject();
jwtObject.setUserName(decoder.getSubject());
jwtObject.setUnqiueId(decoder.getUniqueId());
@ -169,11 +169,48 @@ public class ApiKeyService implements Serializable {
return jwtObject;
}
/**
*
* @param apiKey
* @deprecated use delete (jwtObject) instead
*/
@TransactionAttribute(TransactionAttributeType.REQUIRED)
@Transactional
@Lock(LockType.WRITE)
@Deprecated
public void delete(ApiKeyEntity apiKey) {
em.remove(em.merge(apiKey));
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
@Transactional
@Lock(LockType.WRITE)
public void delete(String authorizationHeader) throws ApiKeyException {
JWTObject jwtObject = getJWTObject(authorizationHeader);
if (jwtObject.isValid()) {
String userName = jwtObject.getUserName();
ApiKeyEntity keyToLogout = getValidKey(userName, jwtObject.getUnqiueId(), authorizationHeader);
if (keyToLogout == null) {
// no valid key found - must not happen, JWTVeryfingFIlter should have catched this
// FIXME - add logging / handle this problem
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("No valid key found, probably user {} has already logged out", userName);
}
throw new ApiKeyException("No valid key found, probably user " + userName + " has already logged out");
} else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Found matching apiKey to logout");
}
em.remove(em.merge(keyToLogout));
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Key deleted, user {} logged out from webservice", userName);
}
}
} else {
throw new ApiKeyException("Provided JWT is not valid");
}
}
}

View File

@ -1,13 +1,13 @@
package de.muehlencord.shared.account.business.account.control;
import de.muehlencord.shared.account.business.account.entity.AccountException;
import de.muehlencord.shared.account.business.account.entity.AccountStatus;
import de.muehlencord.shared.account.business.mail.entity.MailException;
import de.muehlencord.shared.account.business.mail.boundary.MailService;
import de.muehlencord.shared.account.business.account.entity.AccountEntity;
import de.muehlencord.shared.account.business.account.entity.AccountException;
import de.muehlencord.shared.account.business.account.entity.AccountLoginEntity;
import de.muehlencord.shared.account.business.application.entity.ApplicationRoleEntity;
import de.muehlencord.shared.account.business.account.entity.AccountStatus;
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
import de.muehlencord.shared.account.business.application.entity.ApplicationRoleEntity;
import de.muehlencord.shared.account.business.mail.boundary.MailService;
import de.muehlencord.shared.account.business.mail.entity.MailException;
import de.muehlencord.shared.account.util.AccountPU;
import de.muehlencord.shared.account.util.SecurityUtil;
import de.muehlencord.shared.util.DateUtil;
@ -23,10 +23,10 @@ import javax.persistence.NoResultException;
import javax.persistence.Query;
import javax.transaction.Transactional;
import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
@ -156,7 +156,7 @@ public class AccountControl implements Serializable {
@Transactional
public void deleteAccount(AccountEntity account) throws AccountException {
Date now = new Date(); // Todo now in UTC
Date now = DateUtil.getCurrentTimeInUTC();
Subject currentUser = SecurityUtils.getSubject();
String currentUserName = currentUser.getPrincipal().toString();
@ -186,7 +186,7 @@ public class AccountControl implements Serializable {
String randomString = RandomStringUtils.random(40, true, true);
Date validTo = new Date(); // TODO now in UTC
Date validTo = DateUtil.getCurrentTimeInUTC();
validTo = new Date(validTo.getTime() + 1000 * 600); // 10 minutes to react
// TODO rework password reset
@ -217,7 +217,7 @@ public class AccountControl implements Serializable {
/*
if (account.getPasswordResetOngoing() && (account.getPasswordResetHash() != null) && (account.getPasswordResetValidTo() != null)) {
Date now = new Date(); // TODO now in UTC
Date now = DateUtil.getCurrentTimeInUTC();
String storedHash = account.getPasswordResetHash().trim();
if (account.getPasswordResetValidTo().after(now)) {
if (storedHash.equals(resetPasswordToken)) {
@ -248,7 +248,7 @@ public class AccountControl implements Serializable {
}
private void executePasswordReset(AccountEntity account, String newPassword) {
Date now = new Date(); // TODO now in UTC
Date now = DateUtil.getCurrentTimeInUTC();
String hashedPassword = SecurityUtil.createPassword(newPassword);
// account.setAccountPassword(hashedPassword);
@ -294,7 +294,7 @@ public class AccountControl implements Serializable {
public void addLoginError(AccountEntity account) {
// TODO reimplement
// try {
// Date now = new Date(); // TODO now in UTC
// Date now = DateUtil.getCurrentTimeInUTC();
// account.setLastFailedLogin(now);
// account.setFailureCount(account.getFailureCount() + 1);
//

View File

@ -90,10 +90,8 @@ public class ApplicationController {
}
/**
* needs to return link to "Account UI" and not to current selected
* application TODO: ensure only Account UI can call functions where
* appliction can be handed in - all other applications need to call the
* function which use the injected application
* needs to return link to "Account UI" and not to current selected application
* TODO: ensure only Account UI can call functions where appliction can be handed in - all other applications need to call the function which use the injected application
*/
@Produces
public ApplicationEntity getApplication() {

View File

@ -1,8 +1,8 @@
package de.muehlencord.shared.account.business.mail.boundary;
import de.muehlencord.shared.account.business.mail.entity.MailDatamodel;
import de.muehlencord.shared.account.business.mail.entity.MailTemplateException;
import de.muehlencord.shared.account.business.mail.entity.MailTemplateEntity;
import de.muehlencord.shared.account.business.mail.entity.MailTemplateException;
import de.muehlencord.shared.account.util.AccountPU;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
@ -44,7 +44,7 @@ public class MailTemplateService implements Serializable {
}
Configuration configuration = new Configuration(Configuration.VERSION_2_3_23);
configuration.setDefaultEncoding("UTF-8"); // FIXME make encoding configurable
configuration.setDefaultEncoding("UTF-8"); // FIXME - make encoding configurable
configuration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
StringTemplateLoader stringLoader = new StringTemplateLoader();

View File

@ -0,0 +1,109 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package de.muehlencord.shared.account.shiro.authc;
import de.muehlencord.shared.account.business.account.boundary.ApiKeyService;
import de.muehlencord.shared.account.business.account.entity.JWTObject;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author joern.muehlencord
*/
public class JwtMatcher implements CredentialsMatcher {
private static final Logger LOGGER = LoggerFactory.getLogger(JwtMatcher.class);
private final ApiKeyService apiKeyService = lookupApiKeyServiceBean();
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
if (token == null) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("No token available - cannot match credentials");
}
return false;
}
if ((info == null) || (info.getCredentials() == null)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("No authenticationInfo available - cannot match credentials");
}
return false;
}
Object submittedJwtObj = token.getCredentials();
Object storedCredentials = getStoredPassword(info);
if ((submittedJwtObj != null) && (submittedJwtObj.getClass().isAssignableFrom(String.class))) {
String submittedJwt = (String) submittedJwtObj;
if (apiKeyService.validateJWT(submittedJwt)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("JWT is valid, checking if it comes from the correct user");
}
JWTObject jwtObject = apiKeyService.getJWTObject(submittedJwt);
String storedUsername = info.getPrincipals().getPrimaryPrincipal().toString();
if (jwtObject.getUserName().equals(storedUsername)) {
if (jwtObject.getUnqiueId().equals (storedCredentials)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("JWT matches user and password is correct");
}
return true;
} else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("JWT password does not match provided password");
}
return false;
}
} else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("JWT belongs to user {}, but authinfo is from user {} - JWT does not match");
}
return false;
}
} else {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("JWT is invalid");
}
return false;
}
} else {
LOGGER.error("Unexpected authInfoFormat - please check your configuration");
return false;
}
}
protected Object getStoredPassword(AuthenticationInfo storedAccountInfo) {
Object stored = storedAccountInfo != null ? storedAccountInfo.getCredentials() : null;
//fix for https://issues.apache.org/jira/browse/SHIRO-363
if (stored instanceof char[]) {
stored = new String((char[]) stored);
}
return stored;
}
// TODO - can this be injected?
private ApiKeyService lookupApiKeyServiceBean() {
try {
Context c = new InitialContext();
return (ApiKeyService) c.lookup("java:module/ApiKeyService"); // NOI18N
} catch (NamingException ex) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(ex.toString(), ex);
} else {
LOGGER.error(ex.toString());
}
throw new RuntimeException(ex);
}
}
}

View File

@ -0,0 +1,119 @@
package de.muehlencord.shared.account.shiro.filter;
import de.muehlencord.shared.account.business.account.boundary.ApiKeyService;
import de.muehlencord.shared.account.business.account.entity.JWTObject;
import de.muehlencord.shared.account.shiro.token.JWTAuthenticationToken;
import java.io.StringReader;
import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonReader;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.LoggerFactory;
/**
*
* @author Joern Muehlencord <joern at muehlencord.de>
*/
public final class JWTAuthenticationFilter extends AuthenticatingFilter {
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(JWTAuthenticationFilter.class);
protected static final String AUTHORIZATION_HEADER = "Authorization"; // NOI18N
public static final String USERNAME = "username";
public static final String PASSWORD = "password";
private final ApiKeyService apiKeyService = lookupApiKeyServiceBean();
public JWTAuthenticationFilter() {
// FIXME - logging in via JWTAuthenticationFilter does not yet work. Need to set login to anonymous to execute login in rest service
setLoginUrl("/rest/account/login");
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
boolean loggedIn = false;
if (isLoginRequest(request, response) || isLoggedAttempt(request, response)) {
loggedIn = executeLogin(request, response);
}
if (!loggedIn) {
HttpServletResponse httpResponse = WebUtils.toHttp(response);
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
}
return loggedIn;
}
@Override
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
if (isLoginRequest(request, response)) {
String json = IOUtils.toString(request.getInputStream(), "UTF-8"); // FIXME - check charset in request
if (json != null && !json.isEmpty()) {
try (JsonReader jr = Json.createReader(new StringReader(json))) {
JsonObject object = jr.readObject();
String username = object.getString(USERNAME);
String password = object.getString(PASSWORD);
return new UsernamePasswordToken(username, password);
}
}
}
if (isLoggedAttempt(request, response)) {
String jwtToken = getAuthzHeader(request);
if (jwtToken != null) {
return createToken(jwtToken);
}
}
return new UsernamePasswordToken();
}
protected boolean isLoggedAttempt(ServletRequest request, ServletResponse response) {
String authzHeader = getAuthzHeader(request);
return authzHeader != null;
}
protected String getAuthzHeader(ServletRequest request) {
HttpServletRequest httpRequest = WebUtils.toHttp(request);
return httpRequest.getHeader(AUTHORIZATION_HEADER);
}
public JWTAuthenticationToken createToken(String token) {
if (apiKeyService.validateJWT(token)) {
JWTObject jwtObject = apiKeyService.getJWTObject(token);
return new JWTAuthenticationToken(jwtObject.getUserName(), token);
} else {
throw new AuthenticationException("provided API key invalid");
}
}
// TODO - can this be injected?
private ApiKeyService lookupApiKeyServiceBean() {
try {
Context c = new InitialContext();
return (ApiKeyService) c.lookup("java:module/ApiKeyService"); // NOI18N
} catch (NamingException ex) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(ex.toString(), ex);
} else {
LOGGER.error(ex.toString());
}
throw new RuntimeException(ex);
}
}
}

View File

@ -0,0 +1,254 @@
package de.muehlencord.shared.account.shiro.realm;
import de.muehlencord.shared.account.shiro.authc.JwtMatcher;
import de.muehlencord.shared.account.shiro.token.JWTAuthenticationToken;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.UUID;
import org.apache.shiro.authc.AccountException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.AllowAllCredentialsMatcher;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.util.JdbcUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author joern.muehlencord
*/
public class AccountRealm extends JdbcRealm {
private static final Logger LOGGER = LoggerFactory.getLogger(AccountRealm.class);
protected String applicationId = null;
protected String jwtAuthenticationQuery = "select ak.api_key from account a, api_key ak where ak.account = a.id and a.username = ? and a.status not in ('LOCKED','DELETED','DISABLED') ORDER BY ak.issued_on ASC";
protected CredentialsMatcher jwtMatcher = new JwtMatcher();
public AccountRealm() {
this.authenticationQuery = "select al.account_password from account a, account_login al where al.account = a.id and a.username = ? and status not in ('LOCKED','DELETED','DISABLED')";
this.userRolesQuery = "select r.role_name from application_role r, account_role ar, account a WHERE a.username = ? AND a.id = ar.account AND ar.account_role = r.id";
this.permissionsQuery = "select permission_name from application_role appr, role_permission rp, application_permission appp WHERE appr.role_name = ? AND appr.application = ? AND rp.application_role = appr.id AND rp.role_permission = appp.id";
this.permissionsLookupEnabled = true;
}
@Override
public boolean supports(AuthenticationToken token) {
super.supports(token);
return token != null && (token instanceof JWTAuthenticationToken || token instanceof UsernamePasswordToken);
}
public boolean isJwtAuthentication(AuthenticationToken token) {
if (token == null) {
throw new AuthenticationException("empty tokens are not supported by this realm");
}
if (token.getClass().isAssignableFrom(JWTAuthenticationToken.class)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Handling JWTAuthenticationToken");
}
return true;
} else if (token.getClass().isAssignableFrom(UsernamePasswordToken.class)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Handling UsernamePasswordToken");
}
return false;
} else {
throw new AuthenticationException("Handling of " + token.getClass() + " not supported by this realm");
}
}
/**
* overwritten getPermissions. Only change is to inject the applicationId
* into the the query
*
* @param conn the connection to use
* @param username the user to lookup
* @param roleNames the users roles
* @return a list of permissions
* @throws SQLException if the SQL query fails
*/
@Override
protected Set<String> getPermissions(Connection conn, String username, Collection<String> roleNames) throws SQLException {
PreparedStatement ps = null;
Set<String> permissions = new LinkedHashSet<>();
try {
ps = conn.prepareStatement(permissionsQuery);
for (String roleName : roleNames) {
ps.setString(1, roleName);
ps.setObject(2, UUID.fromString(applicationId)); // this is the changed line - rest is the same as in JDBCRealm
ResultSet rs = null;
try {
// Execute query
rs = ps.executeQuery();
// Loop over results and add each returned role to a set
while (rs.next()) {
String permissionString = rs.getString(1);
// Add the permission to the set of permissions
permissions.add(permissionString);
}
} finally {
JdbcUtils.closeResultSet(rs);
}
}
} finally {
JdbcUtils.closeStatement(ps);
}
return permissions;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
if (isJwtAuthentication(token)) {
return doGetJwtAuthenticationInfo(token);
} else {
return super.doGetAuthenticationInfo(token);
}
}
protected AuthenticationInfo doGetJwtAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
JWTAuthenticationToken jwtToken = (JWTAuthenticationToken) token;
String username = jwtToken.getUserName();
// Null username is invalid
if (username == null) {
throw new AccountException("Null usernames are not allowed by this realm.");
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Checking JWT for user {}", username);
}
Connection conn = null;
SimpleAuthenticationInfo info = null;
try {
conn = dataSource.getConnection();
String apiKey = getApiKeyForJwtUser(conn, username);
if (apiKey == null) {
throw new UnknownAccountException("No api key found for user [" + username + "]");
}
info = new SimpleAuthenticationInfo(username, apiKey.toCharArray(), getName());
} catch (SQLException ex) {
final String message = "There was a SQL error while authenticating user [" + username + "]";
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(message, ex);
} else {
LOGGER.error(ex.toString());
}
// Rethrow any SQL errors as an authentication exception
throw new AuthenticationException(message, ex);
} finally {
JdbcUtils.closeConnection(conn);
}
return info;
}
private String getApiKeyForJwtUser(Connection conn, String username) throws SQLException {
String result = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement(jwtAuthenticationQuery);
ps.setString(1, username);
// Execute query
rs = ps.executeQuery();
// loop through result, take last one (by default ordered by issue date ASC)
// we only expect one - application should delete all obsolete ones automatically
while (rs.next()) {
result = rs.getString(1);
}
} finally {
JdbcUtils.closeResultSet(rs);
JdbcUtils.closeStatement(ps);
}
return result;
}
/**
* Asserts that the submitted {@code AuthenticationToken}'s credentials
* match the stored account {@code AuthenticationInfo}'s credentials, and if
* not, throws an {@link AuthenticationException}.
*
* @param token the submitted authentication token
* @param info the AuthenticationInfo corresponding to the given
* {@code token}
* @throws AuthenticationException if the token's credentials do not match
* the stored account credentials.
*/
@Override
protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException {
CredentialsMatcher cm;
if (isJwtAuthentication(token)) {
cm = getJwtMatcher();
} else {
cm = getCredentialsMatcher();
}
if (cm != null) {
if (!cm.doCredentialsMatch(token, info)) {
//not successful - throw an exception to indicate this:
String msg = "Submitted credentials for token [" + token + "] did not match the expected credentials.";
throw new IncorrectCredentialsException(msg);
}
} else {
throw new AuthenticationException("A CredentialsMatcher must be configured in order to verify "
+ "credentials during authentication. If you do not wish for credentials to be examined, you "
+ "can configure an " + AllowAllCredentialsMatcher.class.getName() + " instance.");
}
}
/* *** getter / setter *** */
public String getApplicationId() {
return this.applicationId;
}
public void setApplicationId(String applicationId) {
this.applicationId = applicationId;
}
public String getJwtAuthenticationQuery() {
return jwtAuthenticationQuery;
}
public void setJwtAuthenticationQuery(String jwtAuthenticationQuery) {
this.jwtAuthenticationQuery = jwtAuthenticationQuery;
}
public CredentialsMatcher getJwtMatcher() {
return jwtMatcher;
}
public void setJwtMatcher(CredentialsMatcher jwtMatcher) {
this.jwtMatcher = jwtMatcher;
}
}

View File

@ -1,4 +1,4 @@
package de.muehlencord.shared.account.util;
package de.muehlencord.shared.account.shiro.realm;
import java.util.HashSet;
import java.util.Set;

View File

@ -0,0 +1,50 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package de.muehlencord.shared.account.shiro.token;
import org.apache.shiro.authc.AuthenticationToken;
/**
*
* @author joern.muehlencord
*/
public class JWTAuthenticationToken implements AuthenticationToken {
private String userName;
private String token;
public JWTAuthenticationToken(String userId, String token) {
this.userName = userId;
this.token = token;
}
@Override
public String getPrincipal() {
return getUserName();
}
@Override
public String getCredentials() {
return getToken();
}
public String getUserName() {
return userName;
}
public void setUserName(String userId) {
this.userName = userId;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
}

View File

@ -0,0 +1,22 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package de.muehlencord.shared.account.util;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
/**
*
* @author joern.muehlencord
*/
public class AccountSecurityExceptionMapper implements ExceptionMapper<AccountSecurityException> {
@Override
public Response toResponse(AccountSecurityException ex) {
return Response.status(Response.Status.UNAUTHORIZED).entity(ex.getMessage()).build();
}
}

View File

@ -1,12 +1,12 @@
package de.muehlencord.shared.account.util;
import org.apache.shiro.SecurityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.shiro.authc.credential.DefaultPasswordService;
import org.apache.shiro.crypto.hash.DefaultHashService;
import org.apache.shiro.crypto.hash.Sha512Hash;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*

View File

@ -1,4 +1,4 @@
package de.muehlencord.shared.account.util;
package de.muehlencord.shared.account.shiro.realm;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;