diff --git a/.gitignore b/.gitignore index 8d377bcf35..2115d5fd97 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ \.settings/ \.project \.classpath +\target/**/* +\target/* diff --git a/src/main/java/se/su/dsv/scipro/ApplicationSettings.java b/src/main/java/se/su/dsv/scipro/ApplicationSettings.java index c018687bee..39f25b473d 100644 --- a/src/main/java/se/su/dsv/scipro/ApplicationSettings.java +++ b/src/main/java/se/su/dsv/scipro/ApplicationSettings.java @@ -11,6 +11,7 @@ public class ApplicationSettings { private boolean enableRemoteUserLookup; private String remoteLookupUrl; + private boolean acceptExternalAuthentication; public boolean isEnableRemoteUserLookup() { return enableRemoteUserLookup; @@ -28,4 +29,12 @@ public class ApplicationSettings { return remoteLookupUrl; } + public boolean isAcceptExternalAuthentication(){ + return acceptExternalAuthentication; + } + + public void setAcceptExternalAuthentication(boolean pAcceptExternalAuthentication){ + acceptExternalAuthentication = pAcceptExternalAuthentication; + } + } diff --git a/src/main/java/se/su/dsv/scipro/SciProApplication.java b/src/main/java/se/su/dsv/scipro/SciProApplication.java index d1fd6babce..2b3c943ee1 100644 --- a/src/main/java/se/su/dsv/scipro/SciProApplication.java +++ b/src/main/java/se/su/dsv/scipro/SciProApplication.java @@ -28,6 +28,7 @@ import se.su.dsv.scipro.admin.pages.settings.AdminFinalSeminarSettingsPage; import se.su.dsv.scipro.admin.pages.settings.AdminFinalSeminarSettingsPerProjectClassPage; import se.su.dsv.scipro.admin.pages.settings.AdminGeneralSettingsPage; import se.su.dsv.scipro.admin.pages.settings.AdminPeerSettingsPage; +import se.su.dsv.scipro.admin.pages.settings.AdminServerEnvironmentSettingsPage; import se.su.dsv.scipro.basepages.DemoPage; import se.su.dsv.scipro.basepages.errorpages.AccessDeniedPage; import se.su.dsv.scipro.basepages.errorpages.NotFoundPage; @@ -104,9 +105,8 @@ public class SciProApplication extends RepositoryApplication implements IThemabl /** * Logger instance. - * @TODO Inject */ - private Logger logger = Logger.getLogger(this.getClass()); + private Logger logger = Logger.getLogger(SciProApplication.class); /** * Constructor */ @@ -191,6 +191,7 @@ public class SciProApplication extends RepositoryApplication implements IThemabl mountBookmarkablePage("admin/files", SysAdminFilePage.class); mountBookmarkablePage("admin/allfinalseminars", AdminFinalSeminarPage.class); mountBookmarkablePage("admin/settings", AdminGeneralSettingsPage.class); + mountBookmarkablePage("admin/settings/serverenvironment", AdminServerEnvironmentSettingsPage.class); mountBookmarkablePage("admin/settings/finalseminargeneralsettings", AdminFinalSeminarSettingsPage.class); mountBookmarkablePage("admin/settings/finalseminarprojectlevel", AdminFinalSeminarSettingsPerProjectClassPage.class); mountBookmarkablePage("admin/settings/peer", AdminPeerSettingsPage.class); @@ -310,7 +311,7 @@ public class SciProApplication extends RepositoryApplication implements IThemabl public WebRequest newWebRequest(final HttpServletRequest request){ final WebRequest webRequest = super.newWebRequest(request); if(attemptExternalAuthentication(webRequest)){ - logger.debug("External authentication used"); + logger.debug("External authentication used successfully"); } return webRequest; } @@ -331,19 +332,19 @@ public class SciProApplication extends RepositoryApplication implements IThemabl if(session != null){ if(session.isLoggedIn()){ if(!helper.isRemoteUserValid(session.getUser())){//This check may not be needed and may hinder performance, but better safe than sorry for now. - logger.warn("User is logged in, but conflicting info is supplied via external authentication protocols."); + logger.debug("User is logged in as '"+session.getUser().getEmailAddress()+"', but conflicting info ('"+helper.getExternalAuthRemoteUser()+"') is supplied via external authentication protocols."); } }else{ //logger.info("Attempting sign in with external auth data"); if(!helper.signIn(session)){ - logger.error("User passes external authentication but cannot be signed in."); + logger.error("User '"+helper.getExternalAuthRemoteUser()+"' passes external authentication but cannot be signed in."); }else{ logger.debug("Signed in user '"+helper.getExternalAuthRemoteUser()+"' via external authentication"); return true; } } }else{ - throw new IllegalStateException("External authentication was attempted, but no session was available."); + throw new IllegalStateException("External authentication was attempted, but no session was available for sign in."); } } return false; diff --git a/src/main/java/se/su/dsv/scipro/SciProSession.java b/src/main/java/se/su/dsv/scipro/SciProSession.java index 2bc15ed2b1..3d9f1245e4 100644 --- a/src/main/java/se/su/dsv/scipro/SciProSession.java +++ b/src/main/java/se/su/dsv/scipro/SciProSession.java @@ -207,7 +207,9 @@ public class SciProSession extends WebSession { * @return true if the switch was successful, else false. */ public boolean switchAuthenticatedUser(final String suUser, final String suRealm){ - logger.info("Currently logged in user: '"+user.getEmailAddress()+"' attempting switch to '"+suUser+"'"); + if(!isLoggedIn() || user == null)//Terminate early + return false; + logger.info("Currently logged in user: '"+user.getEmailAddress()+"' attempting switch to '"+suUser+"@"+suRealm+"'"); if(suUser != null && roleDao.isSysadmin(user)){ iRoles.clear(); return signInAuthenticatedUser(suUser, suRealm); diff --git a/src/main/java/se/su/dsv/scipro/admin/pages/AbstractAdminSettingsPage.java b/src/main/java/se/su/dsv/scipro/admin/pages/AbstractAdminSettingsPage.java index 635d34019c..d43bb6968d 100644 --- a/src/main/java/se/su/dsv/scipro/admin/pages/AbstractAdminSettingsPage.java +++ b/src/main/java/se/su/dsv/scipro/admin/pages/AbstractAdminSettingsPage.java @@ -10,6 +10,7 @@ import se.su.dsv.scipro.admin.pages.settings.AdminFinalSeminarSettingsPage; import se.su.dsv.scipro.admin.pages.settings.AdminFinalSeminarSettingsPerProjectClassPage; import se.su.dsv.scipro.admin.pages.settings.AdminGeneralSettingsPage; import se.su.dsv.scipro.admin.pages.settings.AdminPeerSettingsPage; +import se.su.dsv.scipro.admin.pages.settings.AdminServerEnvironmentSettingsPage; import se.su.dsv.scipro.components.AbstractMenuPanel; import se.su.dsv.scipro.icons.ImageIcon; import se.su.dsv.scipro.security.auth.Authorization; @@ -29,6 +30,7 @@ public abstract class AbstractAdminSettingsPage extends AbstractAdminPage { protected List<MenuItem> getItemList() { final List<MenuItem> items = new ArrayList<MenuItem>(); items.add(new MenuItem("General settings", AdminGeneralSettingsPage.class)); + items.add(new MenuItem("Server Environment", AdminServerEnvironmentSettingsPage.class)); items.add(new MenuItem("Final seminar general settings", AdminFinalSeminarSettingsPage.class)); items.add(new MenuItem("Final seminar project level settings", AdminFinalSeminarSettingsPerProjectClassPage.class)); items.add(new MenuItem("Peer settings", AdminPeerSettingsPage.class /*,ImageIcon.ICON_SETTINGS */)); diff --git a/src/main/java/se/su/dsv/scipro/admin/pages/settings/AdminServerEnvironmentSettingsPage.html b/src/main/java/se/su/dsv/scipro/admin/pages/settings/AdminServerEnvironmentSettingsPage.html new file mode 100644 index 0000000000..71a7e5df94 --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/admin/pages/settings/AdminServerEnvironmentSettingsPage.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html + xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd"> +<body> +<wicket:extend> + <h3 class="section">Server/Request environment</h3> + <div style="overflow:auto;height:50%;"> + <ul> + <li wicket:id="requestAttributes"> + <span wicket:id="name">[name]</span>: + <span wicket:id="value">[value]</span> + </li> + </ul> + </div> +</wicket:extend> +</body> +</html> \ No newline at end of file diff --git a/src/main/java/se/su/dsv/scipro/admin/pages/settings/AdminServerEnvironmentSettingsPage.java b/src/main/java/se/su/dsv/scipro/admin/pages/settings/AdminServerEnvironmentSettingsPage.java new file mode 100644 index 0000000000..8ede9d512a --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/admin/pages/settings/AdminServerEnvironmentSettingsPage.java @@ -0,0 +1,49 @@ +package se.su.dsv.scipro.admin.pages.settings; + +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.wicket.PageParameters; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.list.ListItem; +import org.apache.wicket.markup.html.list.ListView; + +import se.su.dsv.scipro.admin.pages.AbstractAdminSettingsPage; +import se.su.dsv.scipro.util.KeyValuePair; + +public class AdminServerEnvironmentSettingsPage extends AbstractAdminSettingsPage { + public AdminServerEnvironmentSettingsPage(final PageParameters pp) { + super(pp); + add(new ListView<KeyValuePair<String>>("requestAttributes",getRequestAttributes()){ + private static final long serialVersionUID = 1L; + @Override + protected void populateItem(ListItem<KeyValuePair<String>> item){ + KeyValuePair<String> pair = item.getModelObject(); + item.add(new Label("name",pair.getKey())); + item.add(new Label("value","'"+pair.getValue()+"'")); + } + }); + } + private List<KeyValuePair<String>> getRequestAttributes(){ + final HttpServletRequest rawRequest = getWebRequestCycle().getWebRequest().getHttpServletRequest(); + List<KeyValuePair<String>> list = new ArrayList<KeyValuePair<String>>(); + list.add(new KeyValuePair<String>("[CALL] getRemoteUser",rawRequest.getRemoteUser())); + list.add(new KeyValuePair<String>("[CALL] getAuthType",rawRequest.getAuthType())); + @SuppressWarnings("rawtypes") Enumeration attributes = rawRequest.getAttributeNames(); + while(attributes.hasMoreElements()){ + final String key = (String)attributes.nextElement(); + final String value = rawRequest.getAttribute(key).toString(); + list.add(new KeyValuePair<String>("[ATTR] "+key,value)); + } + Map<String,String> envs = System.getenv(); + for(String key : envs.keySet()){ + list.add(new KeyValuePair<String>("[ENV] "+key,envs.get(key))); + } + return list; + } +} + diff --git a/src/main/java/se/su/dsv/scipro/security/auth/ExternalAuthenticationRequestHelper.java b/src/main/java/se/su/dsv/scipro/security/auth/ExternalAuthenticationRequestHelper.java index b092537ae1..c70c556893 100644 --- a/src/main/java/se/su/dsv/scipro/security/auth/ExternalAuthenticationRequestHelper.java +++ b/src/main/java/se/su/dsv/scipro/security/auth/ExternalAuthenticationRequestHelper.java @@ -1,6 +1,5 @@ package se.su.dsv.scipro.security.auth; -import java.security.Policy.Parameters; import java.util.Enumeration; import java.util.Map; import java.util.Set; @@ -8,7 +7,10 @@ import java.util.Set; import javax.servlet.http.HttpServletRequest; import org.apache.log4j.Logger; +import org.apache.wicket.injection.web.InjectorHolder; +import org.apache.wicket.spring.injection.annot.SpringBean; +import se.su.dsv.scipro.ApplicationSettings; import se.su.dsv.scipro.SciProSession; import se.su.dsv.scipro.data.dataobjects.User; import se.su.dsv.scipro.data.dataobjects.Username; @@ -30,18 +32,24 @@ public final class ExternalAuthenticationRequestHelper{ //Wrapped request private final HttpServletRequest req; //remote user attribute - private String remoteUser; + private String remoteUser=null; //if remote user is on the username@realm form, this attribute holds the username - private String remoteUserId; + private String remoteUserId=null; //if remote user is on the username@realm form, this attribute holds the realm - private String remoteUserRealm; + private String remoteUserRealm=null; //logger instance private Logger logger = Logger.getLogger(this.getClass()); + @SpringBean + private ApplicationSettings appSettings; /** * Construct a utility wrapper from a servlet request. + * Throws IllegalStateException if the request is null. * @param request */ - public ExternalAuthenticationRequestHelper(final HttpServletRequest request){ + public ExternalAuthenticationRequestHelper(final HttpServletRequest request) throws IllegalStateException{ + if(request==null) + throw new IllegalStateException("Request is null, this is considered illegal."); + InjectorHolder.getInjector().inject(this); req = request; formatUserString(); } @@ -54,7 +62,7 @@ public final class ExternalAuthenticationRequestHelper{ } /** * Exposed query method. - * @return If remote user is on the username@realm form, this attribute holds the userid, else getExternalAuthRemoteUser(). + * @return If remote user is on the username@realm form, this attribute holds the username, else getExternalAuthRemoteUser(). */ public String getExternalAuthRemoteUserId(){ return remoteUserId; @@ -70,7 +78,7 @@ public final class ExternalAuthenticationRequestHelper{ * Internal query method */ private boolean isExternalAuthInfoOnRequest(){ - return (req.getRemoteUser()!=null); + return (remoteUser!=null); } /** * Internal query method @@ -83,12 +91,16 @@ public final class ExternalAuthenticationRequestHelper{ * @return true if the application is configured to accept external authentication and the needed information is available on the request, else false. */ public boolean isExternalAuthSupported(){ - return (true && isExternalAuthInfoOnRequest()); + if(appSettings.isAcceptExternalAuthentication() && !isExternalAuthInfoOnRequest()) + logger.warn("External authentication support is ON, but REMOTE_USER is not populated"); + if(!appSettings.isAcceptExternalAuthentication() && isExternalAuthInfoOnRequest()) + logger.warn("External authentication support is OFF, but REMOTE_USER is populated"); + return (appSettings.isAcceptExternalAuthentication() && isExternalAuthInfoOnRequest()); } /** * Private utility method for dumping headers. */ - public void dumpAuthInfo(){ + private void dumpAuthInfo(){ logger.debug("---Standard methods---"); logger.debug("Request implementation:" + req.getClass().getName()); logger.debug("getAuthType = '" + getExternalAuthType() +"'"); @@ -165,12 +177,12 @@ public final class ExternalAuthenticationRequestHelper{ } } /** - * Signs the stored remote user in on the given SciProSession. - * @param session + * Signs the stored remote user in on the supplied SciProSession. + * @param session If null, method fails gracefully by returning false. * @return true on success, else false. */ public boolean signIn(final SciProSession session){ - if(session != null){ + if(session != null && isExternalAuthSupported()){ //dumpAuthInfo(); return session.signInAuthenticatedUser(getExternalAuthRemoteUserId(), getExternalAuthRemoteUserRealm()); } diff --git a/src/main/java/se/su/dsv/scipro/util/KeyValuePair.java b/src/main/java/se/su/dsv/scipro/util/KeyValuePair.java new file mode 100644 index 0000000000..0b7958d70e --- /dev/null +++ b/src/main/java/se/su/dsv/scipro/util/KeyValuePair.java @@ -0,0 +1,79 @@ +package se.su.dsv.scipro.util; + +import java.io.Serializable; + +/** + * Small utility class for immutable (yes it's immutable and no it's never going to be otherwise) key/value pairs. + * The "value" field is parameterized, but the key is always intended to be a simple String. + * The Serializable properties of this depends on those of the parameterized type. + * Typical usage: + * <code> + * KeyValuePair<SomeType> pair = new KeyValuePair<SomeType>("thisIsAKey",someObject); + * pair.getKey(); + * pair.getValue(); + * </code> + * @param <V> + */ +public final class KeyValuePair<V> implements Serializable{ + private static final long serialVersionUID = 1L; + private final String key; + private final V value; + /** + * Default and only constructor, provide key and value. + * null values are accepted for both key and value, and should be safe to use (yet nonsensical). + * @param key + * @param value + */ + public KeyValuePair(final String key, final V value){ + this.key = key; + this.value = value; + } + /** + * Getter for wrapped key String + * @return The key + */ + public String getKey(){ + return key; + } + /** + * Getter for wrapped Value + * @return The value + */ + public V getValue(){ + return value; + } + /** + * Equals override, behaves in a logical fashion (two objects are equal if both key and value matches). + * Null values are accounted for, ie: two objects with null key+value are considered equal. + */ + @Override + public boolean equals(final Object o){ + if(o==this) + return true; + if(!(o instanceof KeyValuePair)) + return false; + @SuppressWarnings("unchecked") + final KeyValuePair<V> other = (KeyValuePair<V>)o; + return ((key==null?other.key==null:key.equals(other.key)) && + (value==null?other.value==null:value.equals(other.value))); + } + /** + * Hash-code override, uses both components in a standard fashion. + */ + @Override + public int hashCode(){ + final int w = 31; + int result = 17;//Why hello there Mr Bloch, how are we feeling today ? + result = w * result + (key==null?0:key.hashCode()); + result = w * result + (value==null?0:value.hashCode()); + return result; + } + /** + * Standard override, return String format not exposed and subject to change. + * Any parsing of this representation is strongly advised against and done at your own risk. + */ + @Override + public String toString(){ + return ("{"+key+":"+value+"}"); + } +} \ No newline at end of file diff --git a/src/main/resources/applicationContext.xml b/src/main/resources/applicationContext.xml index 5b8bd5f57b..78cb9aa86b 100644 --- a/src/main/resources/applicationContext.xml +++ b/src/main/resources/applicationContext.xml @@ -83,6 +83,8 @@ <property name="enableRemoteUserLookup" value="true"></property> <!-- This property points to the location of the daisy json search --> <property name="remoteLookupUrl" value="https://thesis.dsv.su.se/match/json" /> + <!-- External auth support (via J2EE standard mechanism REMOTE_USER), if true: other authentication mechanics will be bypassed.--> + <property name="acceptExternalAuthentication" value="true"/> </bean> <!-- Defines the class used for lookup in username against a remote server NOW AUTOWIRED AND DEPRECATED, NOT MAINTAINED--> diff --git a/src/test/java/se/su/dsv/scipro/security/auth/TestAuthRoutines.java b/src/test/java/se/su/dsv/scipro/security/auth/TestAuthRoutines.java new file mode 100644 index 0000000000..8df1815fcb --- /dev/null +++ b/src/test/java/se/su/dsv/scipro/security/auth/TestAuthRoutines.java @@ -0,0 +1,192 @@ +package se.su.dsv.scipro.security.auth; + +import java.util.Date; +import java.util.HashSet; +import java.util.Set; + +import javax.servlet.http.HttpServletRequestWrapper; + +import org.apache.wicket.protocol.http.HttpSessionStore; +import org.apache.wicket.session.ISessionStore; +import org.apache.wicket.spring.injection.annot.SpringComponentInjector; +import org.apache.wicket.spring.test.ApplicationContextMock; +import org.apache.wicket.util.tester.WicketTester; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.springframework.orm.jpa.LocalEntityManagerFactoryBean; + +import se.su.dsv.scipro.ApplicationSettings; +import se.su.dsv.scipro.SciProApplication; +import se.su.dsv.scipro.SciProSession; +import se.su.dsv.scipro.data.dao.interfaces.ProjectDao; +import se.su.dsv.scipro.data.dao.interfaces.RoleDao; +import se.su.dsv.scipro.data.dao.interfaces.StringResourceDao; +import se.su.dsv.scipro.data.dao.interfaces.UserDao; +import se.su.dsv.scipro.data.dao.interfaces.UserSettingsDao; +import se.su.dsv.scipro.data.dataobjects.Role; +import se.su.dsv.scipro.data.dataobjects.Student; +import se.su.dsv.scipro.data.dataobjects.SysAdmin; +import se.su.dsv.scipro.data.dataobjects.User; +import se.su.dsv.scipro.data.dataobjects.Username; +import se.su.dsv.scipro.json.IUserLookup; +import se.su.dsv.scipro.repository.util.RepositoryManager; + +public class TestAuthRoutines { + private SciProSession session; + private WicketTester wt; + private User user; + private Role sysAdm; + private IUserLookup fixedLookup; + private ApplicationSettings appSettings; + @Before + public void init(){ + final ApplicationContextMock ac = new ApplicationContextMock(); + //Create mock object in need of config + appSettings = new ApplicationSettings(); + appSettings.setAcceptExternalAuthentication(true); + //Fake a lookup mechanism + fixedLookup = new IUserLookup(){ + @Override + public User lookup(String username) throws Exception{ + if(username.equals("kalle-kula")) + return user; + else + return null; + } + }; + //Create mock user and associated data + user = new User(); + user.setDateCreated(new Date()); + user.setEmailAddress("kalle-kula@dsv.su.se"); + user.setFirstName("Kalle"); + user.setLastName("Kula"); + user.setIdentifier(new Long(666)); + user.setLastModified(new Date()); + Set<Role> roles = new HashSet<Role>(); + //Faked student + Role role = new Student(); + role.setId(new Long(555)); + role.setUser(user); + roles.add(new Student()); + user.setRoles(roles); + //Faked sysadm, added later + sysAdm = new SysAdmin(); + sysAdm.setId(new Long(444)); + Set<Username> usernames = new HashSet<Username>(); + Username username = new Username(); + username.setUserName("kalle-kula"); + username.setRealm("DSV.SU.SE"); + usernames.add(username); + user.setUserNames(usernames); + //Put stuff on bean context + ac.putBean("entityManagerFactory",Mockito.mock(LocalEntityManagerFactoryBean.class)); + ac.putBean("repositoryManager",Mockito.mock(RepositoryManager.class)); + ac.putBean("applicationSettings",appSettings); + ac.putBean("userDao",Mockito.mock(UserDao.class)); + ac.putBean("stringResourceDao",Mockito.mock(StringResourceDao.class)); + RoleDao mockedRoleDao = Mockito.mock(RoleDao.class); + Mockito.when(mockedRoleDao.isSysadmin(user)).thenAnswer(new Answer<Boolean>() { + @Override + public Boolean answer(InvocationOnMock invocation) throws Throwable { + return user.getRoles().contains(sysAdm); + } + }); + ac.putBean("roleDao",mockedRoleDao); + ac.putBean("projectDao",Mockito.mock(ProjectDao.class)); + ac.putBean("userSettingsDao",Mockito.mock(UserSettingsDao.class)); + ac.putBean("userFullLookup",fixedLookup); + //Create tester + wt = new WicketTester(new SciProApplication(){ + @Override + protected ISessionStore newSessionStore(){ + return new HttpSessionStore(this); + } + @Override + protected SpringComponentInjector getSpringInjector() { + return new SpringComponentInjector(this, ac, true); + } + }); + wt.setupRequestAndResponse(); + session = (SciProSession)wt.getWicketSession(); + } + @Test + public void testAuthenticationHelper() throws IllegalStateException { + //Try with faulty request + ExternalAuthenticationRequestHelper helper = new ExternalAuthenticationRequestHelper(wt.getServletRequest()); + Assert.assertFalse(helper.isExternalAuthSupported()); + Assert.assertTrue(helper.getExternalAuthRemoteUser()==null); + Assert.assertTrue(helper.getExternalAuthRemoteUserId()==null); + Assert.assertTrue(helper.getExternalAuthRemoteUserRealm().equals("DSV.SU.SE")); + Assert.assertFalse(helper.isRemoteUserValid(user)); + Assert.assertFalse(helper.signIn(null)); + //Try with conforming request + helper = new ExternalAuthenticationRequestHelper(new HttpServletRequestWrapper(wt.getServletRequest()){ + @Override + public String getRemoteUser(){ + return "kalle-kula@dsv.su.se"; + } + }); + Assert.assertTrue(helper.isExternalAuthSupported()); + Assert.assertTrue(helper.getExternalAuthRemoteUser().equals("kalle-kula@dsv.su.se")); + Assert.assertTrue(helper.getExternalAuthRemoteUserId().equals("kalle-kula")); + Assert.assertTrue(helper.getExternalAuthRemoteUserRealm().equals("DSV.SU.SE")); + Assert.assertTrue(helper.isRemoteUserValid(user)); + } + @Test + public void testTurnOffViaSettings(){ + appSettings.setAcceptExternalAuthentication(false); + ExternalAuthenticationRequestHelper helper = new ExternalAuthenticationRequestHelper(wt.getServletRequest()); + Assert.assertFalse(helper.isExternalAuthSupported()); + } + @Test(expected=IllegalStateException.class) + public void testNullRequest(){ + //At this point, an exception should be thrown + new ExternalAuthenticationRequestHelper(null); + } + @Test(expected=NullPointerException.class) + public void testSessionSignInAndSu(){ + ExternalAuthenticationRequestHelper helper = new ExternalAuthenticationRequestHelper(new HttpServletRequestWrapper(wt.getServletRequest()){ + @Override + public String getRemoteUser(){ + return "kalle-kula@dsv.su.se"; + } + }); + Assert.assertTrue(helper.isExternalAuthSupported()); + Assert.assertTrue(helper.signIn(session)); + Assert.assertTrue(helper.isRemoteUserValid(user)); + Assert.assertTrue(session.isLoggedIn()); + Assert.assertTrue(session.getUser().getIdentifier().equals(user.getIdentifier())); + //User not authorized to switch, this should fail + Assert.assertFalse(session.switchAuthenticatedUser("kalle-kula", "dsv.su.se")); + //Change his roles and try again + Set<Role> roles = user.getRoles(); + sysAdm.setUser(user); + roles.add(sysAdm); + user.setRoles(roles); + Assert.assertTrue(session.switchAuthenticatedUser("kalle-kula", "dsv.su.se")); + Assert.assertTrue(session.getUser().getIdentifier().equals(user.getIdentifier())); + //This should fail with an exception, there is no such user + session.switchAuthenticatedUser("somebody","somewhere.se"); + } + @Test(expected=NullPointerException.class) + public void testFailedAuthenticatedSignIn(){ + ExternalAuthenticationRequestHelper helper = new ExternalAuthenticationRequestHelper(new HttpServletRequestWrapper(wt.getServletRequest()){ + @Override + public String getRemoteUser(){ + return "some-dude@ki.se"; + } + }); + //This should throw exceptions, not sure about this interface (throwing exceptions when authentication passes but no user can be located). + helper.signIn(session); + } + @Test + public void testFailedSwitchAuthentitedUser(){ + Assert.assertFalse(session.isLoggedIn()); + Assert.assertFalse(session.switchAuthenticatedUser("some-dude-who-is-not-real","someplace.se")); + Assert.assertFalse(session.switchAuthenticatedUser("some-dude","someplace.se")); + } +} diff --git a/src/test/java/se/su/dsv/scipro/util/TestKeyValuePair.java b/src/test/java/se/su/dsv/scipro/util/TestKeyValuePair.java new file mode 100644 index 0000000000..ac2c9fd764 --- /dev/null +++ b/src/test/java/se/su/dsv/scipro/util/TestKeyValuePair.java @@ -0,0 +1,22 @@ +package se.su.dsv.scipro.util; + +import org.junit.Assert; +import org.junit.Test; + +public class TestKeyValuePair { + @Test + public void testEqualsOperations() { + KeyValuePair<String> kvpOne = new KeyValuePair<String>("key","value"); + KeyValuePair<String> kvpTwo = new KeyValuePair<String>("key","value"); + KeyValuePair<String> kvpThree = new KeyValuePair<String>("key3","value"); + KeyValuePair<String> kvpFour = new KeyValuePair<String>(null,null); + KeyValuePair<TestKeyValuePair> kvpFive = new KeyValuePair<TestKeyValuePair>("key",this); + + Assert.assertTrue(kvpOne.equals(kvpOne)); + Assert.assertTrue(kvpFour.equals(kvpFour)); + Assert.assertTrue(kvpOne.equals(kvpTwo) && kvpTwo.equals(kvpOne)); + Assert.assertFalse(kvpOne.equals(kvpThree) && kvpThree.equals(kvpOne)); + Assert.assertFalse(kvpFour.equals(kvpThree) && kvpThree.equals(kvpFour)); + Assert.assertFalse(kvpOne.equals(kvpFive) && kvpFive.equals(kvpOne)); + } +} diff --git a/src/test/java/se/su/dsv/scipro/wicket/BaseWicketTest.java b/src/test/java/se/su/dsv/scipro/wicket/BaseWicketTest.java index 976579d098..464495f6a5 100644 --- a/src/test/java/se/su/dsv/scipro/wicket/BaseWicketTest.java +++ b/src/test/java/se/su/dsv/scipro/wicket/BaseWicketTest.java @@ -17,6 +17,7 @@ import org.mockito.stubbing.Answer; import org.springframework.orm.jpa.EntityManagerFactoryInfo; import org.springframework.orm.jpa.LocalEntityManagerFactoryBean; +import se.su.dsv.scipro.ApplicationSettings; import se.su.dsv.scipro.SciProApplication; import se.su.dsv.scipro.data.controllers.FinalSeminarUploadController; import se.su.dsv.scipro.data.dao.interfaces.BoardMessageDao; @@ -95,6 +96,7 @@ public class BaseWicketTest { @Mock GroupEventDao groupEventDao; @Mock HandInActivityDao handInActivityDao; @Mock ScheduleTemplateDao scheduleTemplateDao; + @Mock ApplicationSettings applicationSettings; @Mock RepositoryManager repositoryManager; @Mock StringResourceDao stringResourceDao; diff --git a/src/test/java/se/su/dsv/scipro/wicket/TestWicketPages.java b/src/test/java/se/su/dsv/scipro/wicket/TestWicketPages.java index 33fc6566e3..830ed93d27 100644 --- a/src/test/java/se/su/dsv/scipro/wicket/TestWicketPages.java +++ b/src/test/java/se/su/dsv/scipro/wicket/TestWicketPages.java @@ -8,6 +8,7 @@ import org.mockito.Mockito; import se.su.dsv.scipro.HomePage; import se.su.dsv.scipro.admin.pages.AdminProjectPartnerPage; import se.su.dsv.scipro.admin.pages.SystemMaintenancePage; +import se.su.dsv.scipro.admin.pages.settings.AdminServerEnvironmentSettingsPage; import se.su.dsv.scipro.data.dataobjects.GeneralSystemSettings; import se.su.dsv.scipro.data.dataobjects.Project; import se.su.dsv.scipro.data.dataobjects.ProjectClass; @@ -178,6 +179,11 @@ public class TestWicketPages extends BaseWicketTest { public void testProjectPartnerPage() { tester.startPage(ProjectPartnerPage.class); } + + @Test + public void testAdminServerEnvironmentSettingsPage(){ + tester.startPage(AdminServerEnvironmentSettingsPage.class); + } }