Skip to content

Commit

Permalink
Merge pull request #13 from indigo-dc/secure-rest-api
Browse files Browse the repository at this point in the history
Secure slam REST API using Bearer token
  • Loading branch information
michal-szostak authored Jul 24, 2017
2 parents 24bff00 + c2085cc commit 03067fe
Show file tree
Hide file tree
Showing 6 changed files with 237 additions and 140 deletions.
129 changes: 129 additions & 0 deletions src/main/java/pl/cyfronet/ltos/security/AuthenticationService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package pl.cyfronet.ltos.security;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import javax.net.ssl.HttpsURLConnection;

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.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.client.OAuth2RestOperations;
import org.springframework.stereotype.Service;

import com.agreemount.bean.identity.Identity;
import com.agreemount.bean.identity.provider.IdentityProvider;

import pl.cyfronet.ltos.bean.Role;
import pl.cyfronet.ltos.bean.User;
import pl.cyfronet.ltos.repository.UserRepository;
import pl.cyfronet.ltos.security.AuthenticationProviderDev.UserOperations;

@Service
public class AuthenticationService {
private static final Logger log = LoggerFactory.getLogger(AuthenticationService.class);

@Value("${unity.server.base}")
private String authorizeUrl;

@Value("${unity.server.userInfoAction}")
private String userInfoAction;

@Value("${hostname.verification}")
private Boolean hostnameVerification;

@Autowired
private OAuth2RestOperations restTemplate;

@Autowired
private UserRepository userRepository;

@Autowired
private UserOperations userOperations;

@Autowired
IdentityProvider identityProvider;

//development variable, users whose email matches this will have provider role assigned
@Value("${provider.email:null}")
private String providerEmail;

public void engineLogin(User user) {
Identity identity = new Identity();
identity.setLogin(user.getEmail());
identity.setRoles(user.getRoles().stream().map(entry -> entry.getName()).collect(Collectors.toList()));


identityProvider.setIdentity(identity);
}

public PortalUser getPortalUser() {
return getPortalUser(getUserInfo());
}

private PortalUser getPortalUser(UserInfo userInfo) {
User user = getUser(userInfo);
userInfo.setId(user.getId());

PortalUser.PortalUserBuilder builder = PortalUser.builder();
builder.isAuthenticated(true);
builder.user(user);
builder.authorities(getRoles(user));
builder.principal(userInfo);

return builder.build();
}

private UserInfo getUserInfo() {
if (hostnameVerification.equals(false)) {
HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> {
log.warn("Hostname verification is disabled!!!");
return true;
});
}

return restTemplate.getForObject(authorizeUrl + userInfoAction, UserInfo.class);
}

private User getUser(UserInfo userInfo) {
User user = userRepository.findByEmail(userInfo.getEmail());
if (user == null) {
user = User.builder().name(userInfo.getName()).email(userInfo.getEmail())
.organisationName(userInfo.getOrganisation_name())
.roles(Arrays.asList(userOperations.loadOrCreateRoleByName("manager"))).build();

userRepository.save(user);
}

Role providerRole = userOperations.loadOrCreateRoleByName("provider");
if (user.getEmail().equals(providerEmail) && !user.hasRole("provider")) {
if (!user.getRoles().contains(providerRole)) {
user.getRoles().add(providerRole);
userRepository.save(user);
}
} else { // remove if not in settings
ArrayList<Role> elementsToRemove = new ArrayList<>();
for (Role role : user.getRoles()) {
if (role.getName().equals(providerRole.getName())) {
elementsToRemove.add(role);
}
}
if (elementsToRemove.size() > 0) {
user.getRoles().removeAll(elementsToRemove);
userRepository.save(user);
}
}

return user;
}

private List<SimpleGrantedAuthority> getRoles(User user) {
return user.getRoles().stream()
.map(r -> new SimpleGrantedAuthority("ROLE_" + r.getName().toUpperCase()))
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package pl.cyfronet.ltos.security;

import java.util.List;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand All @@ -12,9 +16,6 @@
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;

import javax.annotation.Resource;
import java.util.List;

/**
* Created by km on 04.08.16.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
package pl.cyfronet.ltos.security;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import javax.net.ssl.HttpsURLConnection;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
Expand All @@ -15,56 +10,28 @@
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.client.OAuth2RestOperations;
import org.springframework.security.oauth2.common.exceptions.InvalidRequestException;
import org.springframework.security.oauth2.common.exceptions.UserDeniedAuthorizationException;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;

import com.agreemount.bean.identity.Identity;
import com.agreemount.bean.identity.provider.IdentityProvider;
import com.google.common.base.Preconditions;

import pl.cyfronet.ltos.bean.Role;
import pl.cyfronet.ltos.bean.User;
import pl.cyfronet.ltos.repository.UserRepository;
import pl.cyfronet.ltos.security.AuthenticationProviderDev.UserOperations;

/**
* Created by km on 04.08.16.
*/
public class OpenIDConnectAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

@Value("${unity.server.base}")
private String authorizeUrl;

@Value("${unity.unauthorizedAction}")
private String unauthorizedAction;

@Value("${hostname.verification}")
private Boolean hostnameVerification;

@Value("${unity.server.userInfoAction}")
private String userInfoAction;

@Autowired
private OAuth2RestOperations restTemplate;

@Autowired
IdentityProvider identityProvider;

@Autowired
private UserRepository userRepository;

@Autowired
private UserOperations userOperations;

//development variable, users whose email matches this will have provider role assigned
@Value("${provider.email:null}")
private String providerEmail;
private AuthenticationService authenticationService;

protected OpenIDConnectAuthenticationFilter(String defaultFilterProcessesUrl) {
super(defaultFilterProcessesUrl);
Expand All @@ -82,89 +49,17 @@ protected OpenIDConnectAuthenticationFilter(String defaultFilterProcessesUrl) {
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
logger.error(request.toString() + " COKOLWIEK " + response.toString());
if (hostnameVerification.equals(false)) {
HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> {
logger.warn("Hostname verification is disabled!!!");
return true;
});
}

PortalUser.PortalUserBuilder builder = PortalUser.builder();
try {
//TODO: poprawne odparsowanie i debugowanie
UserInfo userInfo = restTemplate.getForObject(authorizeUrl + userInfoAction, UserInfo.class);
builder.isAuthenticated(true);
User user = userRepository.findByEmail(userInfo.getEmail());
if (user == null) {
user = User.builder().name(userInfo.getName()).email(userInfo.getEmail())
.organisationName(userInfo.getOrganisation_name())
.roles(Arrays.asList(userOperations.loadOrCreateRoleByName("manager")))
.build();

userRepository.save(user);
}
Role providerRole = userOperations.loadOrCreateRoleByName("provider");
if (user.getEmail().equals(providerEmail) && !user.hasRole("provider")){
if (!user.getRoles().contains(providerRole)) {
user.getRoles().add(providerRole);
userRepository.save(user);
}
}
else { //remove if not in settings
ArrayList<Role> elementsToRemove = new ArrayList<>();
for (Role role : user.getRoles()){
if (role.getName().equals(providerRole.getName())){
elementsToRemove.add(role);
}
}
if(elementsToRemove.size() > 0) {
user.getRoles().removeAll(elementsToRemove);
userRepository.save(user);
}
}

builder.user(user);
userInfo.setId(user.getId());
List<SimpleGrantedAuthority> authorities = new ArrayList<>();

for(Role role : user.getRoles()) {
authorities.add(new SimpleGrantedAuthority("ROLE_"+role.getName().toUpperCase()));
}

builder.authorities(authorities);

Identity identity = getIdentity(user);
Preconditions.checkNotNull(identity, "Identity [%s] was not found", user.getEmail());
identityProvider.setIdentity(identity);

builder.principal(userInfo);
logger.error("userinfo: "+userInfo.toString());
PortalUser portalUser = authenticationService.getPortalUser();
authenticationService.engineLogin(portalUser.getUserBean());

return portalUser;
} catch (UserDeniedAuthorizationException | InvalidRequestException ex) {
RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
redirectStrategy.sendRedirect(request, response, unauthorizedAction);
}

return builder.build();
}

public Identity getIdentity(User user) {
Identity identity = new Identity();
identity.setLogin(user.getEmail());
List<String> roles = user.getRoles().stream().map(entry -> entry.getName()).collect(Collectors.toList());
identity.setRoles(roles);
// List<TeamMembership> teams = user.getTeamMemberships();
// List<TeamMember> teamMembers = new LinkedList<TeamMember>();
// if (teams != null) {
// for (TeamMembership team : teams) {
// for (TeamRole role : team.getTeamRoles()) {
// TeamMember teamMember = new TeamMember(role.getName(), team.getTeam().getName());
// teamMembers.add(teamMember);
// }
// }
// }
// identity.setTeamMembers(teamMembers);
return identity;
return null;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package pl.cyfronet.ltos.security;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.provider.authentication.BearerTokenExtractor;
import org.springframework.web.filter.OncePerRequestFilter;

public class RestAuthenticationFilter extends OncePerRequestFilter {

private static final Logger log = LoggerFactory.getLogger(RestAuthenticationFilter.class);

@Autowired
private OAuth2ClientContext context;

@Autowired
private AuthenticationService authenticationService;

private BearerTokenExtractor extractor = new BearerTokenExtractor();

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {

tryToAuthorize(request);
filterChain.doFilter(request, response);
}

private void tryToAuthorize(HttpServletRequest request) {
try {
Authentication extract = extractor.extract(request);
if (extract != null) {
String jwt = extract.getPrincipal().toString();
context.setAccessToken(new DefaultOAuth2AccessToken(jwt));

PortalUser portalUser = authenticationService.getPortalUser();

authenticationService.engineLogin(portalUser.getUserBean());
SecurityContextHolder.getContext().setAuthentication(portalUser);
}
} catch(Exception e) {
log.info("Unable to authenticate to rest API - wrong token", e);
}
}
}

Loading

0 comments on commit 03067fe

Please sign in to comment.