diff --git a/scm-core/src/main/java/sonia/scm/security/Tokens.java b/scm-core/src/main/java/sonia/scm/security/Tokens.java index 8d15016b56..97a9f29535 100644 --- a/scm-core/src/main/java/sonia/scm/security/Tokens.java +++ b/scm-core/src/main/java/sonia/scm/security/Tokens.java @@ -69,12 +69,33 @@ public final class Tokens * @param username username of the user to authenticate * @param password password of the user to authenticate * - * @return + * @return authentication token */ public static AuthenticationToken createAuthenticationToken( HttpServletRequest request, String username, String password) { - return new UsernamePasswordToken(username, password, + return createAuthenticationToken(request, username, password, false); + } + + /** + * Build an {@link AuthenticationToken} for use with + * {@link Subject#login(org.apache.shiro.authc.AuthenticationToken)}. + * + * + * @param request servlet request + * @param username username of the user to authenticate + * @param password password of the user to authenticate + * @param rememberMe true to remember the user across sessions + * + * @return authentication token + * + * @since 1.31 + */ + public static AuthenticationToken createAuthenticationToken( + HttpServletRequest request, String username, String password, + boolean rememberMe) + { + return new UsernamePasswordToken(username, password, rememberMe, request.getRemoteAddr()); } } diff --git a/scm-core/src/main/java/sonia/scm/web/filter/BasicAuthenticationFilter.java b/scm-core/src/main/java/sonia/scm/web/filter/BasicAuthenticationFilter.java index fc2cc6d681..7db4eaeec6 100644 --- a/scm-core/src/main/java/sonia/scm/web/filter/BasicAuthenticationFilter.java +++ b/scm-core/src/main/java/sonia/scm/web/filter/BasicAuthenticationFilter.java @@ -156,7 +156,7 @@ public class BasicAuthenticationFilter extends HttpFilter } } } - else if (subject.isAuthenticated()) + else if (subject.isAuthenticated() || subject.isRemembered()) { if (logger.isTraceEnabled()) { diff --git a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AuthenticationResource.java b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AuthenticationResource.java index 150d352219..c4e9618329 100644 --- a/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AuthenticationResource.java +++ b/scm-webapp/src/main/java/sonia/scm/api/rest/resources/AuthenticationResource.java @@ -68,6 +68,7 @@ import java.util.Collections; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.DefaultValue; import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.POST; @@ -131,6 +132,7 @@ public class AuthenticationResource * @param response the current http response * @param username the username for the authentication * @param password the password for the authentication + * @param rememberMe true to remember the user across sessions * * @return */ @@ -139,7 +141,8 @@ public class AuthenticationResource @TypeHint(ScmState.class) public ScmState authenticate(@Context HttpServletRequest request, @FormParam("username") String username, - @FormParam("password") String password) + @FormParam("password") String password, @FormParam("rememberMe") + @DefaultValue("false") boolean rememberMe) { ScmState state = null; @@ -148,7 +151,7 @@ public class AuthenticationResource try { subject.login(Tokens.createAuthenticationToken(request, username, - password)); + password, rememberMe)); state = createState(subject); } catch (AuthenticationException ex) @@ -253,11 +256,16 @@ public class AuthenticationResource Response response = null; Subject subject = SecurityUtils.getSubject(); - if (subject.isAuthenticated()) + if (subject.isAuthenticated() || subject.isRemembered()) { if (logger.isDebugEnabled()) { - logger.debug("return state for user {}", subject.getPrincipal()); + String auth = subject.isRemembered() + ? "remembered" + : "authenticated"; + + logger.debug("return state for {} user {}", auth, + subject.getPrincipal()); } ScmState state = createState(subject); diff --git a/scm-webapp/src/main/webapp/resources/js/i18n/de.js b/scm-webapp/src/main/webapp/resources/js/i18n/de.js index 27cba73886..5c595ab914 100644 --- a/scm-webapp/src/main/webapp/resources/js/i18n/de.js +++ b/scm-webapp/src/main/webapp/resources/js/i18n/de.js @@ -88,7 +88,8 @@ if (Sonia.login.Form){ WaitMsgText: 'Übertrage Daten...', failedMsgText: 'Anmeldung fehlgeschlagen!', failedDescriptionText: 'Falscher Benutzername, Passwort oder sie haben nicht\n\ - genug Berechtigungen. Bitte versuchen sie es erneut.' + genug Berechtigungen. Bitte versuchen sie es erneut.', + rememberMeText: 'Angemeldet bleiben' }); } diff --git a/scm-webapp/src/main/webapp/resources/js/login/sonia.login.form.js b/scm-webapp/src/main/webapp/resources/js/login/sonia.login.form.js index 22d037d6a2..aec8decb96 100644 --- a/scm-webapp/src/main/webapp/resources/js/login/sonia.login.form.js +++ b/scm-webapp/src/main/webapp/resources/js/login/sonia.login.form.js @@ -39,11 +39,12 @@ Sonia.login.Form = Ext.extend(Ext.FormPanel,{ WaitMsgText: 'Sending data...', failedMsgText: 'Login failed!', failedDescriptionText: 'Incorrect username, password or not enough permission. Please Try again.', + rememberMeText: 'Remember me', initComponent: function(){ var config = { - labelWidth: 80, + labelWidth: 120, url: restUrl + "authentication/login.json", frame: true, title: this.titleText, @@ -76,6 +77,11 @@ Sonia.login.Form = Ext.extend(Ext.FormPanel,{ scope: this } } + },{ + xtype: 'checkbox', + fieldLabel: this.rememberMeText, + name: 'rememberMe', + inputValue: 'true' }], buttons:[{ text: this.cancelText,