Commit cc5efabd authored by ls1947's avatar ls1947
Browse files

add possibility for service to perform two step 2fa

Service can check service passwords and otp in to seperate steps.
parent 76bddff3
......@@ -223,10 +223,6 @@ public class UserLoginServiceImpl implements UserLoginService, Serializable {
private Map<String, String> ecp(SamlUserEntity user, ServiceEntity service, RegistryEntity registry,
String password, String localHostName) throws RestInterfaceException {
/**
* TODO Check for second factor here. Configurable per service. Then the ldap-facade doesn't
* have to be changed
*/
if (password == null || password.equals("")) {
createLoginInfo(user, registry, UserLoginMethod.LOCAL, UserLoginInfoStatus.FAILED);
throw new LoginFailedException("Password blank");
......
......@@ -66,7 +66,8 @@ public class SshLoginServiceImpl implements SshLoginService {
throw new NoRegistryFoundException("No active registry for user");
if (service.getServiceProps().containsKey("twofa") &&
service.getServiceProps().get("twofa").equalsIgnoreCase("enabled")) {
(service.getServiceProps().get("twofa").equalsIgnoreCase("enabled")
|| service.getServiceProps().get("twofa").equalsIgnoreCase("enabled_twostep"))) {
UserLoginInfoEntity twofaLoginInfo = userLoginInfoDao.findLastByRegistryAndMethod(registry.getId(), UserLoginMethod.TWOFA);
UserLoginInfoEntity localLoginInfo = userLoginInfoDao.findLastByRegistryAndMethod(registry.getId(), UserLoginMethod.LOCAL);
......@@ -137,7 +138,8 @@ public class SshLoginServiceImpl implements SshLoginService {
throw new NoRegistryFoundException("No active registry for user");
if (service.getServiceProps().containsKey("twofa") &&
service.getServiceProps().get("twofa").equalsIgnoreCase("enabled")) {
(service.getServiceProps().get("twofa").equalsIgnoreCase("enabled")
|| service.getServiceProps().get("twofa").equalsIgnoreCase("enabled_twostep"))) {
UserLoginInfoEntity twofaLoginInfo = userLoginInfoDao.findLastByRegistryAndMethod(registry.getId(), UserLoginMethod.TWOFA);
UserLoginInfoEntity localLoginInfo = userLoginInfoDao.findLastByRegistryAndMethod(registry.getId(), UserLoginMethod.LOCAL);
......
package edu.kit.scc.webreg.service.twofa;
import javax.servlet.http.HttpServletRequest;
import edu.kit.scc.webreg.exc.RestInterfaceException;
public interface TwoFaLoginService {
String otpLogin(String eppn, String serviceShortName, String otp, String secret, HttpServletRequest request)
throws TwoFaException, RestInterfaceException;
}
package edu.kit.scc.webreg.service.twofa;
import java.util.Date;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import edu.kit.scc.webreg.dao.RegistryDao;
import edu.kit.scc.webreg.dao.ServiceDao;
import edu.kit.scc.webreg.dao.UserDao;
import edu.kit.scc.webreg.dao.UserLoginInfoDao;
import edu.kit.scc.webreg.entity.RegistryEntity;
import edu.kit.scc.webreg.entity.RegistryStatus;
import edu.kit.scc.webreg.entity.SamlUserEntity;
import edu.kit.scc.webreg.entity.ServiceEntity;
import edu.kit.scc.webreg.entity.UserEntity;
import edu.kit.scc.webreg.entity.UserLoginInfoEntity;
import edu.kit.scc.webreg.entity.UserLoginInfoStatus;
import edu.kit.scc.webreg.entity.UserLoginMethod;
import edu.kit.scc.webreg.event.EventSubmitter;
import edu.kit.scc.webreg.exc.LoginFailedException;
import edu.kit.scc.webreg.exc.NoRegistryFoundException;
import edu.kit.scc.webreg.exc.NoServiceFoundException;
import edu.kit.scc.webreg.exc.NoUserFoundException;
import edu.kit.scc.webreg.exc.RestInterfaceException;
import edu.kit.scc.webreg.service.twofa.linotp.LinotpSimpleResponse;
@Stateless
public class TwoFaLoginServiceImpl implements TwoFaLoginService {
@Inject
private Logger logger;
@Inject
private TwoFaService twoFaService;
@Inject
private UserDao userDao;
@Inject
private ServiceDao serviceDao;
@Inject
private RegistryDao registryDao;
@Inject
private UserLoginInfoDao userLoginInfoDao;
@Inject
private EventSubmitter eventSubmitter;
@Override
public String otpLogin(String eppn, String serviceShortName, String otp, String secret, HttpServletRequest request)
throws TwoFaException, RestInterfaceException {
logger.debug("New otpLogin for {} and {}", eppn, serviceShortName);
UserEntity user = userDao.findByEppn(eppn);
if (user == null)
throw new NoUserFoundException("no such user");
ServiceEntity service = serviceDao.findByShortName(serviceShortName);
if (service == null)
throw new NoServiceFoundException("no such service");
RegistryEntity registry = findRegistry(user, service);
if (registry == null)
throw new NoRegistryFoundException("user not registered for service");
if (! service.getServiceProps().containsKey("twofa_validate_secret")) {
logger.warn("No validation secret configured for service {}. Please configure service property twofa_validate_secret", service.getShortName());
return ":-(";
}
else if ((secret == null) || (! secret.equals(service.getServiceProps().get("twofa_validate_secret")))) {
logger.warn("validation secret mismatch for service {}, {}", service.getShortName(), request.getRemoteAddr());
return ":-(";
}
if (otp == null || otp.equals("")) {
createLoginInfo(user, registry, UserLoginMethod.TWOFA, UserLoginInfoStatus.FAILED);
throw new LoginFailedException("Password blank");
}
LinotpSimpleResponse response = twoFaService.checkToken(user.getId(), otp);
if (!(response.getResult() != null && response.getResult().isStatus() &&
response.getResult().isValue())) {
logger.info("User {} ({}) failed 2fa authentication", user.getEppn(), user.getId());
createLoginInfo(user, registry, UserLoginMethod.TWOFA, UserLoginInfoStatus.FAILED);
return ":-(";
}
else {
logger.info("User {} ({}) 2fa authentication success", user.getEppn(), user.getId());
createLoginInfo(user, registry, UserLoginMethod.TWOFA, UserLoginInfoStatus.SUCCESS);
return ":-)";
}
}
private RegistryEntity findRegistry(UserEntity user, ServiceEntity service) {
RegistryEntity registry = registryDao.findByServiceAndUserAndStatus(service, user, RegistryStatus.ACTIVE);
if (registry == null) {
/*
* Also check for Lost_access registries. They should also be allowed to be rechecked.
*/
registry = registryDao.findByServiceAndUserAndStatus(service, user, RegistryStatus.LOST_ACCESS);
}
if (registry == null) {
/*
* Also check for On_hold registries. They should also be allowed to be rechecked.
*/
registry = registryDao.findByServiceAndUserAndStatus(service, user, RegistryStatus.ON_HOLD);
}
return registry;
}
private void createLoginInfo(UserEntity user, RegistryEntity registry, UserLoginMethod method, UserLoginInfoStatus status) {
UserLoginInfoEntity loginInfo = userLoginInfoDao.createNew();
loginInfo.setUser(user);
loginInfo.setRegistry(registry);
loginInfo.setLoginDate(new Date());
loginInfo.setLoginMethod(method);
loginInfo.setLoginStatus(status);
userLoginInfoDao.persist(loginInfo);
}
}
......@@ -206,7 +206,8 @@ public class RegisterServiceBean implements Serializable {
if (service.getServiceProps().containsKey("twofa") &&
service.getServiceProps().get("twofa").equalsIgnoreCase("enabled")) {
(service.getServiceProps().get("twofa").equalsIgnoreCase("enabled")
|| service.getServiceProps().get("twofa").equalsIgnoreCase("enabled_twostep"))) {
/*
* second factor for service is enabled. Check if user has registered second factor
*/
......
......@@ -53,6 +53,7 @@ public class JaxRsApplicationActivator extends Application {
resources.add(ServiceAdminController.class);
resources.add(UserController.class);
resources.add(SshKeyController.class);
resources.add(OtpController.class);
// Exceptions
resources.add(AssertionExceptionMapper.class);
......
/*******************************************************************************
* Copyright (c) 2014 Michael Simon.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*
* Contributors:
* Michael Simon - initial
******************************************************************************/
package edu.kit.scc.webreg.rest;
import java.io.IOException;
import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import edu.kit.scc.webreg.exc.RestInterfaceException;
import edu.kit.scc.webreg.service.twofa.TwoFaException;
import edu.kit.scc.webreg.service.twofa.TwoFaLoginService;
@Path("/otp")
public class OtpController {
@Inject
private TwoFaLoginService twofaLoginService;
@Path("/simplecheck/{service}/{secret}")
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.TEXT_PLAIN)
public String otpLoginPost(@PathParam("secret") String secret,
@QueryParam("user") String eppn,
@PathParam("service") String serviceShortName,
@FormParam("pass") String otp, @Context HttpServletRequest request)
throws IOException, ServletException, RestInterfaceException {
try {
return twofaLoginService.otpLogin(eppn, serviceShortName, otp, secret, request);
} catch (TwoFaException | RestInterfaceException e) {
return ":-(";
}
}
@Path("/simplecheck/{service}/{secret}")
@GET
@Produces(MediaType.TEXT_PLAIN)
public String otpLoginGet(@PathParam("secret") String secret,
@QueryParam("user") String eppn,
@PathParam("service") String serviceShortName,
@QueryParam("pass") String otp, @Context HttpServletRequest request)
throws IOException, ServletException, RestInterfaceException {
try {
return twofaLoginService.otpLogin(eppn, serviceShortName, otp, secret, request);
} catch (TwoFaException | RestInterfaceException e) {
return ":-(";
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment