Skip to content

Commit

Permalink
Updated to newest upstream version
Browse files Browse the repository at this point in the history
  • Loading branch information
Ununnilium committed Feb 2, 2017
2 parents 749254b + 2fd23bb commit 025b826
Show file tree
Hide file tree
Showing 18 changed files with 685 additions and 285 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ The build will result in a single `.jar` file that is made available in the `tar
## Running the application

```
java -jar shinyproxy-0.4.0.jar
java -jar shinyproxy-0.6.0.jar
```

Navigate to http://localhost:8080 to access the application. If the default configuration is used, authentication will be done against the LDAP server at *ldap.forumsys.com*; to log in one can use the user name "tesla" and password "password".
Expand Down
17 changes: 16 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>eu.openanalytics</groupId>
<artifactId>shinyproxy</artifactId>
<version>0.4.0</version>
<version>0.8.0</version>
<packaging>jar</packaging>

<name>shinyproxy</name>
Expand Down Expand Up @@ -96,6 +96,21 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-core</artifactId>
<version>1.4.4.Final</version>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-servlet</artifactId>
<version>1.4.4.Final</version>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-websockets-jsr</artifactId>
<version>1.4.4.Final</version>
</dependency>
</dependencies>

<build>
Expand Down
13 changes: 8 additions & 5 deletions src/main/java/eu/openanalytics/ShinyProxyApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
package eu.openanalytics;

import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Paths;

import javax.inject.Inject;

Expand All @@ -29,7 +31,6 @@
import org.springframework.core.env.Environment;
import org.springframework.scheduling.annotation.EnableAsync;

import eu.openanalytics.services.AppService;
import eu.openanalytics.services.DockerService;
import eu.openanalytics.services.DockerService.MappingListener;
import io.undertow.Handlers;
Expand All @@ -53,14 +54,16 @@ public class ShinyProxyApplication {
@Inject
DockerService dockerService;

@Inject
AppService appService;

@Inject
Environment environment;

public static void main(String[] args) {
SpringApplication.run(new Class[] { ShinyProxyApplication.class }, args);
SpringApplication app = new SpringApplication(ShinyProxyApplication.class);

boolean hasExternalConfig = Files.exists(Paths.get("application.yml"));
if (!hasExternalConfig) app.setAdditionalProfiles("demo");

app.run(args);
}

@Bean
Expand Down
124 changes: 9 additions & 115 deletions src/main/java/eu/openanalytics/WebSecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,39 +15,26 @@
*/
package eu.openanalytics;

import java.util.HashSet;
import java.util.Set;
import java.util.Arrays;

import javax.inject.Inject;
import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.ldap.core.ContextSource;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import eu.openanalytics.auth.AuthenticationConfigurationFactory;
import eu.openanalytics.components.LogoutHandler;
import eu.openanalytics.services.AppService;
import eu.openanalytics.services.AppService.ShinyApp;
import eu.openanalytics.services.UserService;

/**
* @author Torkild U. Resheim, Itema AS
*/
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
Expand Down Expand Up @@ -75,19 +62,17 @@ public void configure(WebSecurity web) throws Exception {
protected void configure(HttpSecurity http) throws Exception {
http
// must disable or handle in proxy
.csrf()
.disable()
.csrf().disable()
// disable X-Frame-Options
.headers()
.frameOptions()
.sameOrigin();
.headers().frameOptions().disable();

if (hasAuth(environment)) {
if (AuthenticationConfigurationFactory.hasAuth(environment)) {
// Limit access to the app pages
http.authorizeRequests().antMatchers("/login").permitAll();
for (ShinyApp app: appService.getApps()) {
String[] appRoles = appService.getAppRoles(app.getName());
if (appRoles != null && appRoles.length > 0) http.authorizeRequests().antMatchers("/app/" + app.getName()).hasAnyRole(appRoles);
if (app.getGroups() == null || app.getGroups().length == 0) continue;
String[] appRoles = Arrays.stream(app.getGroups()).map(s -> s.toUpperCase()).toArray(i -> new String[i]);
http.authorizeRequests().antMatchers("/app/" + app.getName()).hasAnyRole(appRoles);
}

// Limit access to the admin pages
Expand All @@ -107,11 +92,6 @@ protected void configure(HttpSecurity http) throws Exception {
}
}

private static boolean hasAuth(Environment env) {
String auth = env.getProperty("shiny.proxy.authentication", "").toLowerCase();
return (!auth.isEmpty() && !auth.equals("none"));
}

@Configuration
protected static class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter {

Expand All @@ -120,93 +100,7 @@ protected static class AuthenticationConfiguration extends GlobalAuthenticationC

@Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
if (!hasAuth(environment)) return;

String[] userDnPatterns = { environment.getProperty("shiny.proxy.ldap.user-dn-pattern") };
if (userDnPatterns[0] == null || userDnPatterns[0].isEmpty()) userDnPatterns = new String[0];

String managerDn = environment.getProperty("shiny.proxy.ldap.manager-dn");
if (managerDn != null && managerDn.isEmpty()) managerDn = null;

// Manually instantiate contextSource so it can be passed into authoritiesPopulator below.
String ldapUrl = environment.getProperty("shiny.proxy.ldap.url");
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(ldapUrl);
if (managerDn != null) {
contextSource.setUserDn(managerDn);
contextSource.setPassword(environment.getProperty("shiny.proxy.ldap.manager-password"));
}
contextSource.afterPropertiesSet();

// Manually instantiate authoritiesPopulator because it uses a customized class.
CNLdapAuthoritiesPopulator authoritiesPopulator = new CNLdapAuthoritiesPopulator(
contextSource,
environment.getProperty("shiny.proxy.ldap.group-search-base", ""));
authoritiesPopulator.setGroupRoleAttribute("cn");
authoritiesPopulator.setGroupSearchFilter(environment.getProperty("shiny.proxy.ldap.group-search-filter", "(uniqueMember={0})"));

auth
.ldapAuthentication()
.userDnPatterns(userDnPatterns)
.userSearchBase(environment.getProperty("shiny.proxy.ldap.user-search-base", ""))
.userSearchFilter(environment.getProperty("shiny.proxy.ldap.user-search-filter"))
.ldapAuthoritiesPopulator(authoritiesPopulator)
.contextSource(contextSource);
}
}

private static class CNLdapAuthoritiesPopulator extends DefaultLdapAuthoritiesPopulator {

private static final Log logger = LogFactory.getLog(DefaultLdapAuthoritiesPopulator.class);

public CNLdapAuthoritiesPopulator(ContextSource contextSource, String groupSearchBase) {
super(contextSource, groupSearchBase);
}

@Override
public Set<GrantedAuthority> getGroupMembershipRoles(String userDn, String username) {
if (getGroupSearchBase() == null) {
return new HashSet<GrantedAuthority>();
}

Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();

if (logger.isDebugEnabled()) {
logger.debug("Searching for roles for user '" + username + "', DN = " + "'"
+ userDn + "', with filter " + getGroupSearchFilter()
+ " in search base '" + getGroupSearchBase() + "'");
}

// Here's the modification: added {2}, which refers to the user cn if available.
Set<String> userRoles = getLdapTemplate().searchForSingleAttributeValues(
getGroupSearchBase(), getGroupSearchFilter(),
new String[] { userDn, username, getCn(userDn) }, getGroupRoleAttribute());

if (logger.isDebugEnabled()) {
logger.debug("Roles from search: " + userRoles);
}

for (String role : userRoles) {

if (isConvertToUpperCase()) {
role = role.toUpperCase();
}

authorities.add(new SimpleGrantedAuthority(getRolePrefix() + role));
}

return authorities;
}

private String getCn(String dn) {
try {
LdapName ln = new LdapName(dn);
for (Rdn rdn : ln.getRdns()) {
if (rdn.getType().equalsIgnoreCase("CN")) {
return rdn.getValue().toString();
}
}
} catch (InvalidNameException e) {}
return "";
AuthenticationConfigurationFactory.configure(auth, environment);
}
}
}
Loading

0 comments on commit 025b826

Please sign in to comment.