diff --git a/src/main/java/de/thm/arsnova/services/UserService.java b/src/main/java/de/thm/arsnova/services/UserService.java index ca3bf8f3f0f319970421e77c90b85858fa4e3ec8..edecbeb396cb801121a3223677cf320ad03a8812 100644 --- a/src/main/java/de/thm/arsnova/services/UserService.java +++ b/src/main/java/de/thm/arsnova/services/UserService.java @@ -1,5 +1,8 @@ package de.thm.arsnova.services; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -7,16 +10,22 @@ import java.util.Map.Entry; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Pattern; import javax.annotation.PreDestroy; import org.apache.commons.lang.RandomStringUtils; +import org.apache.commons.lang.StringUtils; import org.scribe.up.profile.facebook.FacebookProfile; import org.scribe.up.profile.google.Google2Profile; import org.scribe.up.profile.twitter.TwitterProfile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.mail.MailException; +import org.springframework.mail.MailSender; +import org.springframework.mail.SimpleMailMessage; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; @@ -27,6 +36,7 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.keygen.BytesKeyGenerator; import org.springframework.security.crypto.keygen.KeyGenerators; +import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; @@ -38,6 +48,7 @@ import de.thm.arsnova.entities.User; import de.thm.arsnova.exceptions.UnauthorizedException; import de.thm.arsnova.socket.ARSnovaSocketIOServer; +@Service public class UserService implements IUserService { private static final int DEFAULT_SCHEDULER_DELAY_MS = 60000; @@ -59,7 +70,20 @@ public class UserService implements IUserService { @Autowired private ARSnovaSocketIOServer socketIoServer; - + + @Autowired + private MailSender mailSender; + + @Autowired + private SimpleMailMessage regMailTemplate; + + @Value("${security.user-db.allowed-email-domains}") + private String allowedEmailDomains; + + @Value("${security.arsnova-url}") + private String arsnovaUrl; + + private Pattern mailPattern; private BytesKeyGenerator keygen; private BCryptPasswordEncoder encoder; @@ -260,7 +284,15 @@ public class UserService implements IUserService { if (null == keygen) { keygen = KeyGenerators.secureRandom(32); } - + + if (null == mailPattern) { + parseMailAddressPattern(); + } + + if (null == mailPattern || !mailPattern.matcher(username).matches()) { + return null; + } + if (null != databaseDao.getUser(username)) { return null; } @@ -271,7 +303,12 @@ public class UserService implements IUserService { dbUser.setActivationKey(RandomStringUtils.randomAlphanumeric(32)); dbUser.setCreation(System.currentTimeMillis()); - return databaseDao.createOrUpdateUser(dbUser); + DbUser result = databaseDao.createOrUpdateUser(dbUser); + if (null != result) { + sendActivationEmail(result); + } + + return result; } public String encodePassword(String password) { @@ -282,12 +319,50 @@ public class UserService implements IUserService { return encoder.encode(password); } + public void sendActivationEmail(DbUser dbUser) { + SimpleMailMessage msg = new SimpleMailMessage(regMailTemplate); + String activationUrl = MessageFormat.format("{0}/auth/activate?username={1}&key={2}", arsnovaUrl, dbUser.getUsername(), dbUser.getActivationKey()); + msg.setTo(dbUser.getUsername()); + msg.setText(MessageFormat.format(msg.getText(), activationUrl)); + LOGGER.debug("Activation mail body: {}", msg.getText()); + + try { + LOGGER.info("Sending activation mail to {}", dbUser.getUsername()); + mailSender.send(msg); + } catch (MailException e) { + LOGGER.warn("Activation mail could not be sent: {}", e); + } + } + + private void parseMailAddressPattern() { + /* TODO: Add Unicode support */ + + List<String> domainList = Arrays.asList(allowedEmailDomains.split(",")); + + if (domainList.size() > 0) { + List<String> patterns = new ArrayList<String>(); + if (domainList.contains("*")) { + patterns.add("([a-z0-9-]\\.)+[a-z0-9-]"); + } else { + Pattern patternPattern = Pattern.compile("[a-z0-9.*-]+", Pattern.CASE_INSENSITIVE); + for (String patternStr : domainList) { + if (patternPattern.matcher(patternStr).matches()) { + patterns.add(patternStr.replaceAll("[.]", "[.]").replaceAll("[*]", "[a-z0-9-]+?")); + } + } + } + + mailPattern = Pattern.compile("[a-z0-9._-]+?@(" + StringUtils.join(patterns, "|") + ")", Pattern.CASE_INSENSITIVE); + LOGGER.info("Allowed e-mail addresses (pattern) for registration: " + mailPattern.pattern()); + } + } + @Override public DbUser updateDbUser(DbUser dbUser) { if (null != dbUser.getId()) { return databaseDao.createOrUpdateUser(dbUser); } - + return null; } } diff --git a/src/main/webapp/WEB-INF/spring/spring-main.xml b/src/main/webapp/WEB-INF/spring/spring-main.xml index 7152abfce0beab0ab446bc600e853081b810f9f0..f66e53fff1dc47966c073e962ba7ceb43b9b0018 100644 --- a/src/main/webapp/WEB-INF/spring/spring-main.xml +++ b/src/main/webapp/WEB-INF/spring/spring-main.xml @@ -48,7 +48,15 @@ <bean id="userSessionAspect" class="de.thm.arsnova.aop.UserSessionAspect" /> - <bean id="userService" scope="singleton" class="de.thm.arsnova.services.UserService" /> + <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl"> + <property name="host" value="${mail.host}"/> + </bean> + + <bean id="templateMessage" class="org.springframework.mail.SimpleMailMessage"> + <property name="from" value="${mail.sender.address} <${mail.sender.address}>"/> + <property name="subject" value="${security.user-db.registration-mail.subject}"/> + <property name="text" value="${security.user-db.registration-mail.body}"/> + </bean> <!-- Example of connector client configuration --> <!-- Uncomment bean definition to activate connector --> diff --git a/src/main/webapp/arsnova.properties.example b/src/main/webapp/arsnova.properties.example index ab44df3147f58e0427cdcbd71f60b983bfcfaea4..d70a76a1b784e3a600db62a3fb9d13992cfd9865 100644 --- a/src/main/webapp/arsnova.properties.example +++ b/src/main/webapp/arsnova.properties.example @@ -3,8 +3,14 @@ security.arsnova-url=http://localhost:8080 security.guest.enabled=true security.guest.lecturer.enabled=true +security.user-db.enabled=true +security.user-db.allowed-email-domains=* +security.user-db.registration-mail.subject=ARSnova Registration +security.user-db.registration-mail.body=Welcome to ARSnova!\n\nPlease confirm your registration by visiting the following web address:\n{0}\n\nAfterwards, you can log into ARSnova with your e-mail address and password. + security.ldap.enabled=true security.ldap.url=ldap://example.com:33389/dc=example,dc=com +security.ldap.user-dn-pattern=uid={0},ou=arsnova security.ldap.user-search-filter=(uid={0}) security.ldap.user-search-base="ou=people" @@ -27,6 +33,10 @@ security.ssl=false security.keystore=/etc/arsnova.thm.de.jks security.storepass=arsnova +mail.sender.name=ARSnova +mail.sender.address= +mail.host= + # minutes, after which the feedback is deleted feedback.cleanup=10 diff --git a/src/test/resources/arsnova.properties.example b/src/test/resources/arsnova.properties.example index df77f33e61c3ace0d15b97c2a2c4557027029eea..d70a76a1b784e3a600db62a3fb9d13992cfd9865 100644 --- a/src/test/resources/arsnova.properties.example +++ b/src/test/resources/arsnova.properties.example @@ -1,33 +1,54 @@ security.arsnova-url=http://localhost:8080 + +security.guest.enabled=true +security.guest.lecturer.enabled=true + +security.user-db.enabled=true +security.user-db.allowed-email-domains=* +security.user-db.registration-mail.subject=ARSnova Registration +security.user-db.registration-mail.body=Welcome to ARSnova!\n\nPlease confirm your registration by visiting the following web address:\n{0}\n\nAfterwards, you can log into ARSnova with your e-mail address and password. + +security.ldap.enabled=true +security.ldap.url=ldap://example.com:33389/dc=example,dc=com +security.ldap.user-dn-pattern=uid={0},ou=arsnova +security.ldap.user-search-filter=(uid={0}) +security.ldap.user-search-base="ou=people" + +security.cas.enabled=true security.cas-server-url=https://cas.thm.de/cas -security.facebook.key=318531508227494 -security.facebook.secret=e3f38cfc72bb63e35641b637081a6177 +security.facebook.enabled=true +security.facebook.key= +security.facebook.secret= -security.twitter.key=PEVtidSG0HzSrxVRPpsCXw -security.twitter.secret=mC0HOvxiEgqwdDWCcDoy3q75nUQPu1bYRp1ncHWGd0 +security.twitter.enabled=true +security.twitter.key= +security.twitter.secret= -security.google.key=110959746118.apps.googleusercontent.com -security.google.secret=CkzUJZswY8rjWCCYnHVovyGA +security.google.enabled=true +security.google.key= +security.google.secret= security.ssl=false security.keystore=/etc/arsnova.thm.de.jks security.storepass=arsnova -security.ldap.url=ldap://example.com:389/dc=example,dc=com -security.ldap.user-search-filter=(uid={0}) -security.ldap.user-search-base= +mail.sender.name=ARSnova +mail.sender.address= +mail.host= + +# minutes, after which the feedback is deleted +feedback.cleanup=10 couchdb.host=localhost couchdb.port=5984 couchdb.name=arsnova - -# minutes, after which the feedback is deleted -feedback.cleanup=10 +couchdb.username=admin +couchdb.password= socketio.ip=0.0.0.0 socketio.port=10443 connector.uri=http://localhost:8080/connector-service connector.username=test -connector.password=test \ No newline at end of file +connector.password=test