updated libraries
updated to JUNIT5
This commit is contained in:
@ -54,15 +54,20 @@
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
|
||||
@ -163,8 +163,9 @@ public class ApiKeyService implements Serializable {
|
||||
@Transactional
|
||||
@Lock(LockType.WRITE)
|
||||
public ApiKeyObject createNewApiKey(String userName, short expirationInMinutes) throws ApiKeyException {
|
||||
if ((password == null || issuer == null) || (userName == null)) {
|
||||
LOGGER.error("password, issuer or username not set in, please validate configuration");
|
||||
if (password == null || issuer == null || userName == null) {
|
||||
String hint = "password, issuer or username not set in, please validate configuration";
|
||||
throw new ApiKeyException(hint);
|
||||
}
|
||||
Date now = DateUtil.getCurrentTimeInUTC();
|
||||
ZonedDateTime issuedOn = ZonedDateTime.ofInstant(now.toInstant(), ZoneId.of("UTC"));
|
||||
|
||||
@ -15,7 +15,6 @@
|
||||
*/
|
||||
package de.muehlencord.shared.account.business.config.boundary;
|
||||
|
||||
import de.muehlencord.shared.db.ControllerException;
|
||||
import de.muehlencord.shared.account.business.account.entity.Account;
|
||||
import de.muehlencord.shared.account.business.account.entity.AccountEntity;
|
||||
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
|
||||
@ -23,6 +22,7 @@ import de.muehlencord.shared.account.business.config.entity.ConfigEntity;
|
||||
import de.muehlencord.shared.account.business.config.entity.ConfigEntityPK;
|
||||
import de.muehlencord.shared.account.business.config.entity.ConfigException;
|
||||
import de.muehlencord.shared.account.util.AccountPU;
|
||||
import de.muehlencord.shared.db.ControllerException;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@ -37,6 +37,7 @@ import javax.inject.Inject;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.Query;
|
||||
import javax.transaction.Transactional;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -121,7 +122,7 @@ public class ConfigService implements Serializable {
|
||||
|
||||
// if config value is not found null has been returned
|
||||
// in this case the value to return is the defaultValue
|
||||
if (configValue == null) {
|
||||
if (StringUtils.isEmpty(configValue)) {
|
||||
configValue = defaultValue;
|
||||
}
|
||||
|
||||
|
||||
@ -15,10 +15,10 @@
|
||||
*/
|
||||
package de.muehlencord.shared.account.business.instance.boundary;
|
||||
|
||||
import de.muehlencord.shared.db.ControllerException;
|
||||
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
|
||||
import de.muehlencord.shared.account.business.config.boundary.ConfigService;
|
||||
import de.muehlencord.shared.account.business.config.entity.ConfigException;
|
||||
import de.muehlencord.shared.db.ControllerException;
|
||||
import javax.annotation.PreDestroy;
|
||||
import javax.enterprise.context.ApplicationScoped;
|
||||
import javax.enterprise.context.Initialized;
|
||||
|
||||
@ -1,202 +1,201 @@
|
||||
/*
|
||||
* Copyright 2018 joern.muehlencord.
|
||||
*
|
||||
* 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 de.muehlencord.shared.account.presentation;
|
||||
|
||||
import de.muehlencord.shared.account.business.account.control.AccountControl;
|
||||
import de.muehlencord.shared.account.business.account.entity.AccountEntity;
|
||||
import de.muehlencord.shared.jeeutil.FacesUtil;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import javax.ejb.EJB;
|
||||
import javax.faces.context.ExternalContext;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.view.ViewScoped;
|
||||
import javax.inject.Named;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.authc.AuthenticationException;
|
||||
import org.apache.shiro.authc.UsernamePasswordToken;
|
||||
import org.apache.shiro.web.util.WebUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author joern.muehlencord
|
||||
*/
|
||||
@Named(value = "loginView")
|
||||
@ViewScoped
|
||||
public class LoginView implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -1164860380769648432L;
|
||||
|
||||
@EJB
|
||||
private AccountControl accountService;
|
||||
|
||||
private String username = null;
|
||||
private String password = null;
|
||||
private boolean rememberMe = false;
|
||||
|
||||
private String resetPasswordToken = null;
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(LoginView.class.getName());
|
||||
|
||||
public void authenticate() {
|
||||
|
||||
// Example using most common scenario of username/password pair:
|
||||
UsernamePasswordToken token = new UsernamePasswordToken(getUsername(), getPassword());
|
||||
|
||||
// "Remember Me" built-in:
|
||||
token.setRememberMe(rememberMe);
|
||||
Subject currentUser = SecurityUtils.getSubject();
|
||||
LOGGER.info("Trying to login user {}", username);
|
||||
|
||||
try {
|
||||
currentUser.login(token);
|
||||
LOGGER.info("User {} logged in", username);
|
||||
// user logged in, update account entity
|
||||
AccountEntity account = accountService.getAccountEntity(username, true);
|
||||
accountService.updateLogin(account);
|
||||
|
||||
// redirect to home
|
||||
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
|
||||
ServletResponse servletResponse = (ServletResponse) ec.getResponse();
|
||||
String fallbackUrl = "/web/index.xhtml"; // TODO make configurable
|
||||
// ec.redirect(url);
|
||||
if (LOGGER.isTraceEnabled()) {
|
||||
LOGGER.trace("redirecting to {}, fallbackUrl={}", servletResponse.toString(), fallbackUrl);
|
||||
}
|
||||
|
||||
WebUtils.redirectToSavedRequest((ServletRequest) ec.getRequest(), servletResponse, fallbackUrl);
|
||||
} catch (IOException | AuthenticationException ex) {
|
||||
// Could catch a subclass of AuthenticationException if you like
|
||||
String hint = "Error while authenticating user " + username;
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(hint, ex);
|
||||
}
|
||||
|
||||
if (ex.getMessage() != null) {
|
||||
hint += "Reason: " + ex.getMessage();
|
||||
} else {
|
||||
hint += "Reason: " + ex.toString();
|
||||
}
|
||||
if ((ex.getCause() != null) && (ex.getCause().getMessage() != null)) {
|
||||
hint += "Rootcause: " + ex.getMessage();
|
||||
|
||||
LOGGER.error(hint);
|
||||
}
|
||||
FacesUtil.addGlobalErrorMessage("Login failed", hint);
|
||||
|
||||
AccountEntity account = accountService.getAccountEntity(username, false);
|
||||
if (account != null) {
|
||||
accountService.addLoginError(account);
|
||||
}
|
||||
} finally {
|
||||
token.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void logout() {
|
||||
Subject currentUser = SecurityUtils.getSubject();
|
||||
try {
|
||||
currentUser.logout();
|
||||
|
||||
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
|
||||
|
||||
// ensure faces session is invalidated so beans are destroyed
|
||||
ec.invalidateSession();
|
||||
|
||||
// check if redirect shall be executed
|
||||
// default setting is yes to /login.xhtml
|
||||
// can be overwritten using parameters
|
||||
// de.muehlencord.shared.account.loginview.executeredirect boolean true/false
|
||||
// de.muehlencord.shared.account.loginview.redirecttarget path to redirect to (without external context, will be added automatically)
|
||||
String executeRedirectString = ec.getInitParameter("de.muehlencord.shared.account.loginview.executeredirect");
|
||||
boolean executeRedirect = true;
|
||||
if (executeRedirectString != null) {
|
||||
executeRedirect = Boolean.parseBoolean(executeRedirectString);
|
||||
}
|
||||
|
||||
String redirectTarget = ec.getInitParameter("de.muehlencord.shared.account.loginview.redirecttarget");
|
||||
if ((redirectTarget == null) || (redirectTarget.equals(""))) {
|
||||
redirectTarget = "/login.xhtml";
|
||||
}
|
||||
|
||||
if (executeRedirect) {
|
||||
String url = ec.getRequestContextPath() + redirectTarget;
|
||||
ec.redirect(url);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public String executePasswordReset() {
|
||||
boolean passwordResetted = accountService.resetPassword(username, password, resetPasswordToken);
|
||||
if (passwordResetted) {
|
||||
// TODO add email notification on updated user account
|
||||
FacesUtil.addGlobalInfoMessage("Password resetted", null);
|
||||
return login();
|
||||
} else {
|
||||
// TODO add email notificaton on failed password reset
|
||||
FacesUtil.addGlobalErrorMessage("Password reset failed", null);
|
||||
return login();
|
||||
}
|
||||
}
|
||||
|
||||
/* **** naviation rules **** */
|
||||
public String login() {
|
||||
return "/login.xhtml"; // TODO make configurable
|
||||
}
|
||||
|
||||
/* *** getter / setter */
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String un) {
|
||||
this.username = un;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String pw) {
|
||||
this.password = pw;
|
||||
}
|
||||
|
||||
public boolean isRememberMe() {
|
||||
return rememberMe;
|
||||
}
|
||||
|
||||
public void setRememberMe(boolean rememberMe) {
|
||||
this.rememberMe = rememberMe;
|
||||
}
|
||||
|
||||
public String getResetPasswordToken() {
|
||||
return resetPasswordToken;
|
||||
}
|
||||
|
||||
public void setResetPasswordToken(String resetPasswordToken) {
|
||||
this.resetPasswordToken = resetPasswordToken;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2018 joern.muehlencord.
|
||||
*
|
||||
* 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 de.muehlencord.shared.account.presentation;
|
||||
|
||||
import de.muehlencord.shared.account.business.account.control.AccountControl;
|
||||
import de.muehlencord.shared.account.business.account.entity.AccountEntity;
|
||||
import de.muehlencord.shared.jeeutil.FacesUtil;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import javax.ejb.EJB;
|
||||
import javax.faces.context.ExternalContext;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.faces.view.ViewScoped;
|
||||
import javax.inject.Named;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.authc.AuthenticationException;
|
||||
import org.apache.shiro.authc.UsernamePasswordToken;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.apache.shiro.web.util.WebUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author joern.muehlencord
|
||||
*/
|
||||
@Named(value = "loginView")
|
||||
@ViewScoped
|
||||
public class LoginView implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -1164860380769648432L;
|
||||
|
||||
@EJB
|
||||
private AccountControl accountService;
|
||||
|
||||
private String username = null;
|
||||
private String password = null;
|
||||
private boolean rememberMe = false;
|
||||
|
||||
private String resetPasswordToken = null;
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(LoginView.class.getName());
|
||||
|
||||
public void authenticate() {
|
||||
|
||||
// Example using most common scenario of username/password pair:
|
||||
UsernamePasswordToken token = new UsernamePasswordToken(getUsername(), getPassword());
|
||||
|
||||
// "Remember Me" built-in:
|
||||
token.setRememberMe(rememberMe);
|
||||
Subject currentUser = SecurityUtils.getSubject();
|
||||
LOGGER.info("Trying to login user {}", username);
|
||||
|
||||
try {
|
||||
currentUser.login(token);
|
||||
LOGGER.info("User {} logged in", username);
|
||||
// user logged in, update account entity
|
||||
AccountEntity account = accountService.getAccountEntity(username, true);
|
||||
accountService.updateLogin(account);
|
||||
|
||||
// redirect to home
|
||||
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
|
||||
ServletResponse servletResponse = (ServletResponse) ec.getResponse();
|
||||
String fallbackUrl = "/web/index.xhtml"; // TODO make configurable
|
||||
// ec.redirect(url);
|
||||
if (LOGGER.isTraceEnabled()) {
|
||||
LOGGER.trace("redirecting to {}, fallbackUrl={}", servletResponse.toString(), fallbackUrl);
|
||||
}
|
||||
|
||||
WebUtils.redirectToSavedRequest((ServletRequest) ec.getRequest(), servletResponse, fallbackUrl);
|
||||
} catch (IOException | AuthenticationException ex) {
|
||||
// Could catch a subclass of AuthenticationException if you like
|
||||
String hint = "Error while authenticating user " + username;
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(hint, ex);
|
||||
}
|
||||
|
||||
if (ex.getMessage() != null) {
|
||||
hint += "Reason: " + ex.getMessage();
|
||||
} else {
|
||||
hint += "Reason: " + ex.toString();
|
||||
}
|
||||
if ((ex.getCause() != null) && (ex.getCause().getMessage() != null)) {
|
||||
hint += "Rootcause: " + ex.getMessage();
|
||||
|
||||
LOGGER.error(hint);
|
||||
}
|
||||
FacesUtil.addGlobalErrorMessage("Login failed", hint);
|
||||
|
||||
AccountEntity account = accountService.getAccountEntity(username, false);
|
||||
if (account != null) {
|
||||
accountService.addLoginError(account);
|
||||
}
|
||||
} finally {
|
||||
token.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void logout() {
|
||||
Subject currentUser = SecurityUtils.getSubject();
|
||||
try {
|
||||
currentUser.logout();
|
||||
|
||||
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
|
||||
|
||||
// ensure faces session is invalidated so beans are destroyed
|
||||
ec.invalidateSession();
|
||||
|
||||
// check if redirect shall be executed
|
||||
// default setting is yes to /login.xhtml
|
||||
// can be overwritten using parameters
|
||||
// de.muehlencord.shared.account.loginview.executeredirect boolean true/false
|
||||
// de.muehlencord.shared.account.loginview.redirecttarget path to redirect to (without external context, will be added automatically)
|
||||
String executeRedirectString = ec.getInitParameter("de.muehlencord.shared.account.loginview.executeredirect");
|
||||
boolean executeRedirect = true;
|
||||
if (executeRedirectString != null) {
|
||||
executeRedirect = Boolean.parseBoolean(executeRedirectString);
|
||||
}
|
||||
|
||||
String redirectTarget = ec.getInitParameter("de.muehlencord.shared.account.loginview.redirecttarget");
|
||||
if ((redirectTarget == null) || (redirectTarget.equals(""))) {
|
||||
redirectTarget = "/login.xhtml";
|
||||
}
|
||||
|
||||
if (executeRedirect) {
|
||||
String url = ec.getRequestContextPath() + redirectTarget;
|
||||
ec.redirect(url);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public String executePasswordReset() {
|
||||
boolean passwordResetted = accountService.resetPassword(username, password, resetPasswordToken);
|
||||
if (passwordResetted) {
|
||||
// TODO add email notification on updated user account
|
||||
FacesUtil.addGlobalInfoMessage("Password resetted", null);
|
||||
return login();
|
||||
} else {
|
||||
// TODO add email notificaton on failed password reset
|
||||
FacesUtil.addGlobalErrorMessage("Password reset failed", null);
|
||||
return login();
|
||||
}
|
||||
}
|
||||
|
||||
/* **** naviation rules **** */
|
||||
public String login() {
|
||||
return "/login.xhtml"; // TODO make configurable
|
||||
}
|
||||
|
||||
/* *** getter / setter */
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String un) {
|
||||
this.username = un;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String pw) {
|
||||
this.password = pw;
|
||||
}
|
||||
|
||||
public boolean isRememberMe() {
|
||||
return rememberMe;
|
||||
}
|
||||
|
||||
public void setRememberMe(boolean rememberMe) {
|
||||
this.rememberMe = rememberMe;
|
||||
}
|
||||
|
||||
public String getResetPasswordToken() {
|
||||
return resetPasswordToken;
|
||||
}
|
||||
|
||||
public void setResetPasswordToken(String resetPasswordToken) {
|
||||
this.resetPasswordToken = resetPasswordToken;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,172 +1,169 @@
|
||||
/*
|
||||
* Copyright 2018 joern.muehlencord.
|
||||
*
|
||||
* 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 de.muehlencord.shared.account.shiro.filter;
|
||||
|
||||
import java.io.IOException;
|
||||
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.ServletException;
|
||||
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.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;
|
||||
|
||||
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 de.muehlencord.shared.account.util.AccountSecurityException;
|
||||
import de.muehlencord.shared.jeeutil.restexfw.APIException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @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
|
||||
protected static final String USERNAME = "username"; // NOI18N
|
||||
protected static final String PASSWORD = "password"; // NOI18N
|
||||
|
||||
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 (LOGGER.isTraceEnabled()) {
|
||||
LOGGER.trace("found jwtToke in header = {}", jwtToken);
|
||||
}
|
||||
|
||||
if (jwtToken != null) {
|
||||
JWTObject jwtObject = apiKeyService.getJWTObject(jwtToken);
|
||||
return new JWTAuthenticationToken(jwtObject.getUserName(), jwtToken);
|
||||
}
|
||||
}
|
||||
|
||||
return new UsernamePasswordToken();
|
||||
}
|
||||
|
||||
private boolean isLoggedAttempt(ServletRequest request, ServletResponse response) {
|
||||
String authzHeader = getAuthzHeader(request);
|
||||
return authzHeader != null;
|
||||
}
|
||||
|
||||
private String getAuthzHeader(ServletRequest request) {
|
||||
HttpServletRequest httpRequest = WebUtils.toHttp(request);
|
||||
return httpRequest.getHeader(AUTHORIZATION_HEADER);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overwrite cleanup to ensure no exception is thrown if an
|
||||
* AccountSecurityException / APIException is raised during login. As long
|
||||
* as the user is not logged in JERSEYs ExceptionMapper and intercepor
|
||||
* classes are overruled by Shiro.
|
||||
*
|
||||
* @param request the incoming request
|
||||
* @param response the response to return
|
||||
* @param existing the raised exception
|
||||
* @throws ServletException may be thrown by AuthenticatingFilter.cleanup if
|
||||
* existing is not a AccountSecurityException
|
||||
* @throws IOException may be thrown by AuthenticatingFilter.cleanup if
|
||||
* existing is not a AccountSecurityException
|
||||
*/
|
||||
@Override
|
||||
protected void cleanup(ServletRequest request, ServletResponse response, Exception existing) throws ServletException, IOException {
|
||||
if ((existing != null) && (existing.getClass().isAssignableFrom(AccountSecurityException.class))) {
|
||||
HttpServletResponse httpResponse = WebUtils.toHttp(response);
|
||||
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
} else if ((existing != null) && (existing.getClass().isAssignableFrom(APIException.class))) {
|
||||
APIException apiException = (APIException) existing;
|
||||
|
||||
HttpServletResponse httpResponse = WebUtils.toHttp(response);
|
||||
httpResponse.setStatus(apiException.getHttpResponse().getStatus());
|
||||
httpResponse.addHeader(APIException.HTTP_HEADER_X_ERROR, apiException.getHttpResponse().getHeaderString(APIException.HTTP_HEADER_X_ERROR));
|
||||
httpResponse.addHeader(APIException.HTTP_HEADER_X_ERROR_CODE, apiException.getHttpResponse().getHeaderString(APIException.HTTP_HEADER_X_ERROR_CODE));
|
||||
|
||||
if (apiException.getHttpResponse().getHeaderString(APIException.HTTP_HEADER_X_ROOT_CAUSE) != null) {
|
||||
httpResponse.addHeader(APIException.HTTP_HEADER_X_ROOT_CAUSE, apiException.getHttpResponse().getHeaderString(APIException.HTTP_HEADER_X_ROOT_CAUSE));
|
||||
}
|
||||
} else {
|
||||
super.cleanup(request, response, existing);
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2018 joern.muehlencord.
|
||||
*
|
||||
* 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 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 de.muehlencord.shared.account.util.AccountSecurityException;
|
||||
import de.muehlencord.shared.jeeutil.restexfw.APIException;
|
||||
import java.io.IOException;
|
||||
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.ServletException;
|
||||
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.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
|
||||
protected static final String USERNAME = "username"; // NOI18N
|
||||
protected static final String PASSWORD = "password"; // NOI18N
|
||||
|
||||
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 (LOGGER.isTraceEnabled()) {
|
||||
LOGGER.trace("found jwtToke in header = {}", jwtToken);
|
||||
}
|
||||
|
||||
if (jwtToken != null) {
|
||||
JWTObject jwtObject = apiKeyService.getJWTObject(jwtToken);
|
||||
return new JWTAuthenticationToken(jwtObject.getUserName(), jwtToken);
|
||||
}
|
||||
}
|
||||
|
||||
return new UsernamePasswordToken();
|
||||
}
|
||||
|
||||
private boolean isLoggedAttempt(ServletRequest request, ServletResponse response) {
|
||||
String authzHeader = getAuthzHeader(request);
|
||||
return authzHeader != null;
|
||||
}
|
||||
|
||||
private String getAuthzHeader(ServletRequest request) {
|
||||
HttpServletRequest httpRequest = WebUtils.toHttp(request);
|
||||
return httpRequest.getHeader(AUTHORIZATION_HEADER);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overwrite cleanup to ensure no exception is thrown if an
|
||||
* AccountSecurityException / APIException is raised during login. As long
|
||||
* as the user is not logged in JERSEYs ExceptionMapper and intercepor
|
||||
* classes are overruled by Shiro.
|
||||
*
|
||||
* @param request the incoming request
|
||||
* @param response the response to return
|
||||
* @param existing the raised exception
|
||||
* @throws ServletException may be thrown by AuthenticatingFilter.cleanup if
|
||||
* existing is not a AccountSecurityException
|
||||
* @throws IOException may be thrown by AuthenticatingFilter.cleanup if
|
||||
* existing is not a AccountSecurityException
|
||||
*/
|
||||
@Override
|
||||
protected void cleanup(ServletRequest request, ServletResponse response, Exception existing) throws ServletException, IOException {
|
||||
if ((existing != null) && (existing.getClass().isAssignableFrom(AccountSecurityException.class))) {
|
||||
HttpServletResponse httpResponse = WebUtils.toHttp(response);
|
||||
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
} else if ((existing != null) && (existing.getClass().isAssignableFrom(APIException.class))) {
|
||||
APIException apiException = (APIException) existing;
|
||||
|
||||
HttpServletResponse httpResponse = WebUtils.toHttp(response);
|
||||
httpResponse.setStatus(apiException.getHttpResponse().getStatus());
|
||||
httpResponse.addHeader(APIException.HTTP_HEADER_X_ERROR, apiException.getHttpResponse().getHeaderString(APIException.HTTP_HEADER_X_ERROR));
|
||||
httpResponse.addHeader(APIException.HTTP_HEADER_X_ERROR_CODE, apiException.getHttpResponse().getHeaderString(APIException.HTTP_HEADER_X_ERROR_CODE));
|
||||
|
||||
if (apiException.getHttpResponse().getHeaderString(APIException.HTTP_HEADER_X_ROOT_CAUSE) != null) {
|
||||
httpResponse.addHeader(APIException.HTTP_HEADER_X_ROOT_CAUSE, apiException.getHttpResponse().getHeaderString(APIException.HTTP_HEADER_X_ROOT_CAUSE));
|
||||
}
|
||||
} else {
|
||||
super.cleanup(request, response, existing);
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,21 +1,98 @@
|
||||
package de.muehlencord.shared.account.business.account.boundary;
|
||||
|
||||
import org.junit.Test;
|
||||
import de.muehlencord.shared.account.business.account.control.AccountControl;
|
||||
import de.muehlencord.shared.account.business.account.entity.AccountEntity;
|
||||
import de.muehlencord.shared.account.business.application.entity.ApplicationRoleEntity;
|
||||
import de.muehlencord.shared.account.business.config.boundary.ConfigService;
|
||||
import de.muehlencord.shared.account.business.config.entity.ConfigException;
|
||||
import de.muehlencord.shared.account.dao.ApiKeyObject;
|
||||
import de.muehlencord.shared.db.ControllerException;
|
||||
import java.util.ArrayList;
|
||||
import javax.persistence.EntityManager;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord <joern at muehlencord.de>
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class ApiKeyServiceTest {
|
||||
|
||||
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(ApiKeyServiceTest.class);
|
||||
|
||||
ApiKeyService apiKeyService;
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
apiKeyService = new ApiKeyService();
|
||||
apiKeyService.configService = mock(ConfigService.class);
|
||||
try {
|
||||
when(apiKeyService.configService.getConfigValue(anyString(), anyString(), anyBoolean())).thenReturn("120");
|
||||
when(apiKeyService.configService.getConfigValue(anyString())).thenAnswer(new Answer<String>() {
|
||||
@Override
|
||||
public String answer(InvocationOnMock invocation) throws Throwable {
|
||||
Object[] args = invocation.getArguments();
|
||||
String configKey = args[0].toString();
|
||||
switch (configKey) {
|
||||
case "rest.password":
|
||||
return "secret";
|
||||
case "rest.issuer":
|
||||
return "ApiKeyServiceTest";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (ConfigException | ControllerException ex) {
|
||||
LOGGER.error(ex.getMessage());
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug("Detailed stacktrace", new Object[]{ex});
|
||||
}
|
||||
fail("An exception occured");
|
||||
}
|
||||
apiKeyService.accountControl = mock(AccountControl.class);
|
||||
when(apiKeyService.accountControl.getAccountEntity(anyString(), anyBoolean())).thenAnswer(new Answer<AccountEntity>() {
|
||||
@Override
|
||||
public AccountEntity answer(InvocationOnMock iom) throws Throwable {
|
||||
Object[] args = iom.getArguments();
|
||||
String userName = args[0].toString();
|
||||
boolean loadRoles = (boolean) args[1];
|
||||
AccountEntity account = new AccountEntity();
|
||||
account.setUsername(userName);
|
||||
account.setFirstname("FirstName");
|
||||
account.setLastname("LastName");
|
||||
if (loadRoles) {
|
||||
account.setApplicationRoleList(new ArrayList<>());
|
||||
ApplicationRoleEntity exampleRoleEntity = new ApplicationRoleEntity();
|
||||
exampleRoleEntity.setRoleName("Example Role");
|
||||
account.getApplicationRoleList().add(exampleRoleEntity);
|
||||
}
|
||||
return account;
|
||||
}
|
||||
|
||||
});
|
||||
apiKeyService.em = mock (EntityManager.class);
|
||||
apiKeyService.init();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateApiKey() {
|
||||
try {
|
||||
ApiKeyService apiKeyService = new ApiKeyService();
|
||||
apiKeyService.createNewApiKey("web", (short) 120);
|
||||
ApiKeyObject apiKeyObject = apiKeyService.createNewApiKey("web", (short) 120);
|
||||
assertNotNull(apiKeyObject);
|
||||
LOGGER.info("authToken: "+apiKeyObject.getAuthToken());
|
||||
} catch (ApiKeyException ex) {
|
||||
LOGGER.error(ex.getMessage());
|
||||
if (LOGGER.isDebugEnabled()) {
|
||||
|
||||
@ -1,76 +1,76 @@
|
||||
/*
|
||||
* Copyright 2018 joern.muehlencord.
|
||||
*
|
||||
* 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 de.muehlencord.shared.account.business.config.boundary;
|
||||
|
||||
import de.muehlencord.shared.account.business.account.entity.AccountEntity;
|
||||
import de.muehlencord.shared.account.business.account.entity.AccountLoginEntity;
|
||||
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
|
||||
import de.muehlencord.shared.account.business.config.entity.ConfigEntity;
|
||||
import de.muehlencord.shared.account.business.config.entity.ConfigEntityPK;
|
||||
import java.util.UUID;
|
||||
import javax.persistence.EntityManager;
|
||||
import org.junit.Test;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author joern.muehlencord
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ConfigServiceTest {
|
||||
|
||||
@InjectMocks
|
||||
private ConfigService configService;
|
||||
|
||||
@Mock
|
||||
private EntityManager entityManagerMock;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
ApplicationEntity application = new ApplicationEntity();
|
||||
application.setId(UUID.randomUUID());
|
||||
application.setApplicationName("Test App");
|
||||
|
||||
AccountEntity account = new AccountEntity();
|
||||
account.setUsername("system");
|
||||
AccountLoginEntity login = new AccountLoginEntity();
|
||||
login.setAccount (account);
|
||||
account.setAccountLogin(login);
|
||||
|
||||
ConfigEntityPK pk = new ConfigEntityPK(application, "account.maxFailedLogins", account);
|
||||
ConfigEntity configEntity = new ConfigEntity (pk);
|
||||
configEntity.setConfigValue("7");
|
||||
when (entityManagerMock.find(ConfigEntity.class, "account.maxFailedLogins")).thenReturn (configEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
// TODO move to account test
|
||||
public void testGetMaxFailedLogins() {
|
||||
// configService.init();
|
||||
// assertEquals ("maxFailedLogins", 7, configService.getMaxFailedLogins());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2018 joern.muehlencord.
|
||||
*
|
||||
* 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 de.muehlencord.shared.account.business.config.boundary;
|
||||
|
||||
import de.muehlencord.shared.account.business.account.entity.AccountEntity;
|
||||
import de.muehlencord.shared.account.business.account.entity.AccountLoginEntity;
|
||||
import de.muehlencord.shared.account.business.application.entity.ApplicationEntity;
|
||||
import de.muehlencord.shared.account.business.config.entity.ConfigEntity;
|
||||
import de.muehlencord.shared.account.business.config.entity.ConfigEntityPK;
|
||||
import java.util.UUID;
|
||||
import javax.persistence.EntityManager;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author joern.muehlencord
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class ConfigServiceTest {
|
||||
|
||||
@InjectMocks
|
||||
private ConfigService configService;
|
||||
|
||||
@Mock
|
||||
private EntityManager entityManagerMock;
|
||||
|
||||
@BeforeEach
|
||||
public void init() {
|
||||
ApplicationEntity application = new ApplicationEntity();
|
||||
application.setId(UUID.randomUUID());
|
||||
application.setApplicationName("Test App");
|
||||
|
||||
AccountEntity account = new AccountEntity();
|
||||
account.setUsername("system");
|
||||
AccountLoginEntity login = new AccountLoginEntity();
|
||||
login.setAccount (account);
|
||||
account.setAccountLogin(login);
|
||||
|
||||
ConfigEntityPK pk = new ConfigEntityPK(application, "account.maxFailedLogins", account);
|
||||
ConfigEntity configEntity = new ConfigEntity (pk);
|
||||
configEntity.setConfigValue("7");
|
||||
when (entityManagerMock.find(ConfigEntity.class, "account.maxFailedLogins")).thenReturn (configEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
// TODO move to account test
|
||||
public void testGetMaxFailedLogins() {
|
||||
// configService.init();
|
||||
// assertEquals ("maxFailedLogins", 7, configService.getMaxFailedLogins());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -1,68 +1,75 @@
|
||||
/*
|
||||
* Copyright 2018 joern.muehlencord.
|
||||
*
|
||||
* 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 de.muehlencord.shared.account.shiro.realm;
|
||||
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.authc.AuthenticationException;
|
||||
import org.apache.shiro.authc.UsernamePasswordToken;
|
||||
import org.apache.shiro.config.IniSecurityManagerFactory;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.junit.Test;
|
||||
import org.apache.shiro.mgt.SecurityManager;
|
||||
import static org.junit.Assume.assumeNotNull;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord <joern at muehlencord.de>
|
||||
*/
|
||||
public class UserNameActiveDirectoryRealmTest {
|
||||
|
||||
@Test
|
||||
public void testUsernameLogin() {
|
||||
String userName = "user.name";
|
||||
String password = "secret";
|
||||
testLogin(userName, password);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmailaddressLogin() {
|
||||
String userName = "user.name@domain.com";
|
||||
String password = "secret";
|
||||
testLogin(userName, password);
|
||||
}
|
||||
|
||||
@Test(expected=AuthenticationException.class)
|
||||
public void testWrongUserNamePassword() {
|
||||
String userName = "test123";
|
||||
String password = "secret";
|
||||
testLogin(userName, password);
|
||||
}
|
||||
|
||||
private void testLogin(String userName, String password) throws AuthenticationException {
|
||||
assumeNotNull(UserNameActiveDirectoryRealmTest.class.getResource("/shiro.ini"));
|
||||
|
||||
IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
|
||||
SecurityManager securityManager = factory.getInstance();
|
||||
SecurityUtils.setSecurityManager(securityManager);
|
||||
|
||||
UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
|
||||
Subject currentUser = SecurityUtils.getSubject();
|
||||
|
||||
currentUser.login(token);
|
||||
System.out.println("Logged in");
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2018 joern.muehlencord.
|
||||
*
|
||||
* 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 de.muehlencord.shared.account.shiro.realm;
|
||||
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.authc.AuthenticationException;
|
||||
import org.apache.shiro.authc.UsernamePasswordToken;
|
||||
import org.apache.shiro.config.IniSecurityManagerFactory;
|
||||
import org.apache.shiro.mgt.SecurityManager;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import static org.junit.jupiter.api.Assumptions.assumeFalse;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord <joern at muehlencord.de>
|
||||
*/
|
||||
public class UserNameActiveDirectoryRealmTest {
|
||||
|
||||
@Test
|
||||
public void testUsernameLogin() {
|
||||
String userName = "root";
|
||||
String password = "secret";
|
||||
testLogin(userName, password);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
public void testEmailaddressLogin() {
|
||||
String userName = "user.name@domain.com";
|
||||
String password = "secret";
|
||||
Assertions.assertThrows(AuthenticationException.class, () -> {
|
||||
testLogin(userName, password);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrongUserNamePassword() {
|
||||
String userName = "test123";
|
||||
String password = "secret";
|
||||
Assertions.assertThrows(AuthenticationException.class, () -> {
|
||||
testLogin(userName, password);
|
||||
});
|
||||
}
|
||||
|
||||
private void testLogin(String userName, String password) throws AuthenticationException {
|
||||
assumeFalse(UserNameActiveDirectoryRealmTest.class.getResource("/shiro.ini") == null);
|
||||
|
||||
IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
|
||||
SecurityManager securityManager = factory.getInstance();
|
||||
SecurityUtils.setSecurityManager(securityManager);
|
||||
|
||||
UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
|
||||
Subject currentUser = SecurityUtils.getSubject();
|
||||
|
||||
currentUser.login(token);
|
||||
System.out.println("Logged in");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,32 +1,32 @@
|
||||
/*
|
||||
* Copyright 2018 joern.muehlencord.
|
||||
*
|
||||
* 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 de.muehlencord.shared.account.util;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord <joern at muehlencord.de>
|
||||
*/
|
||||
public class SecurityUtilTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void testCreatePassword() {
|
||||
System.out.println (SecurityUtil.createPassword("secret"));
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright 2018 joern.muehlencord.
|
||||
*
|
||||
* 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 de.muehlencord.shared.account.util;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Joern Muehlencord <joern at muehlencord.de>
|
||||
*/
|
||||
public class SecurityUtilTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void testCreatePassword() {
|
||||
System.out.println (SecurityUtil.createPassword("secret"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
25
account/src/test/resources/shiro.ini
Normal file
25
account/src/test/resources/shiro.ini
Normal file
@ -0,0 +1,25 @@
|
||||
# =============================================================================
|
||||
# Tutorial INI configuration
|
||||
#
|
||||
# Usernames/passwords are based on the classic Mel Brooks' film "Spaceballs" :)
|
||||
# =============================================================================
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Users and their (optional) assigned roles
|
||||
# username = password, role1, role2, ..., roleN
|
||||
# -----------------------------------------------------------------------------
|
||||
[users]
|
||||
root = secret, admin
|
||||
guest = guest, guest
|
||||
presidentskroob = 12345, president
|
||||
darkhelmet = ludicrousspeed, darklord, schwartz
|
||||
lonestarr = vespa, goodguy, schwartz
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Roles with assigned permissions
|
||||
# roleName = perm1, perm2, ..., permN
|
||||
# -----------------------------------------------------------------------------
|
||||
[roles]
|
||||
admin = *
|
||||
schwartz = lightsaber:*
|
||||
goodguy = winnebago:drive:eagle5
|
||||
Reference in New Issue
Block a user