package org.nextprot.api.security.service.impl; import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nextprot.api.security.service.JWTCodec; import org.nextprot.api.security.service.NextprotAuth0Endpoint; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import com.auth0.Auth0User; import com.auth0.jwt.JWTVerifier; import com.auth0.spring.security.auth0.Auth0JWTToken; import com.auth0.spring.security.auth0.Auth0TokenException; public class NextprotAuthProvider implements AuthenticationProvider, InitializingBean { private JWTVerifier jwtVerifier; private String clientSecret; private String clientId; private final Log logger = LogFactory.getLog(NextprotAuthProvider.class); //@Autowired //private NextprotAuth0Endpoint nextprotAuth0Endpoint; @Autowired private UserDetailsService userDetailsService; @Autowired private JWTCodec<Map<String, Object>> codec; public Authentication authenticate(Authentication authentication) throws AuthenticationException { String token = ((Auth0JWTToken) authentication).getJwt(); this.logger.debug("Trying to authenticate with token: " + token); try { Map<String, Object> map = null; Auth0User auth0User = null; //Should put this in 2 different providers if(token.split("\\.").length == 3){ //it's the id token (JWT) map = jwtVerifier.verify(token); this.logger.debug("Authenticating with JWT"); } /* else { // not using access token for now try { this.logger.debug("Will ask auth0 service"); //in case we send the access token auth0User = nextprotAuth0Endpoint.fetchUser(token); this.logger.debug("Authenticating with access token (asking auth0 endpoint)" + auth0User); }catch (Exception e){ e.printStackTrace(); this.logger.error(e.getMessage()); throw new SecurityException("client id not found"); } }*/ this.logger.debug("Decoded JWT token" + map); UserDetails userDetails; // UI Widget map if ((auth0User != null && auth0User.getEmail() != null) || (map != null && map.containsKey("email"))) { String username = null; if(auth0User != null && auth0User.getEmail() != null) { username = auth0User.getEmail(); } else { username = (String) map.get("email"); } if (username != null) { userDetails = userDetailsService.loadUserByUsername(username); authentication.setAuthenticated(true); return createSuccessAuthentication(userDetails, map); } else return null; } // Codec map else if (map != null && map.containsKey("payload")) { Map<String, Object> payload = codec.decodeJWT(token); String username = (String) payload.get("email"); if (username != null) { userDetails = userDetailsService.loadUserByUsername(username); userDetails.getAuthorities().clear(); List<String> auths = (List<String>) payload.get("authorities"); for (String authority : auths) { ((Set<GrantedAuthority>)userDetails.getAuthorities()).add(new SimpleGrantedAuthority(authority)); } authentication.setAuthenticated(true); return createSuccessAuthentication(userDetails, map); } else { return null; } } else throw new SecurityException("client id not found"); /*//TODO add the application here or as another provider else if (map.containsKey("app_id")) { long appId = (Long) map.get("app_id"); UserApplication userApp = userApplicationService.getUserApplication(appId); if (userApp.hasUserDataAccess()) { userDetails = userDetailsService.loadUserByUsername(userApp.getOwner()); if (userDetails == null) { userService.createUser(buildUserFromAuth0(map)); } userDetails = userDetailsService.loadUserByUsername(userApp.getOwner()); } }*/ } catch (InvalidKeyException e) { //this.logger.error("InvalidKeyException thrown while decoding JWT token " + e.getLocalizedMessage()); throw new Auth0TokenException(e); } catch (NoSuchAlgorithmException e) { //this.logger.error("NoSuchAlgorithmException thrown while decoding JWT token " + e.getLocalizedMessage()); throw new Auth0TokenException(e); } catch (IllegalStateException e) { //this.logger.error("IllegalStateException thrown while decoding JWT token " + e.getLocalizedMessage()); throw new Auth0TokenException(e); } catch (SignatureException e) { //this.logger.error("SignatureException thrown while decoding JWT token " + e.getLocalizedMessage()); throw new Auth0TokenException(e); } catch (IOException e) { //this.logger.error("IOException thrown while decoding JWT token " + e.getLocalizedMessage()); throw new Auth0TokenException("invalid token", e); } } @Override public boolean supports(Class<?> authentication) { return Auth0JWTToken.class.isAssignableFrom(authentication); } @Override public void afterPropertiesSet() throws Exception { if ((this.clientSecret == null) || (this.clientId == null)) { throw new RuntimeException("client secret and client id are not set for Auth0AuthenticationProvider"); } this.jwtVerifier = new JWTVerifier(this.clientSecret, this.clientId); } public String getClientSecret() { return this.clientSecret; } @Value("${auth0.clientSecret}") public void setClientSecret(String clientSecret) { this.clientSecret = clientSecret; } public String getClientId() { return this.clientId; } @Value("${auth0.clientId}") public void setClientId(String clientId) { this.clientId = clientId; } /** * Creates a successful {@link Authentication} object * * @return the successful authentication token */ private final Authentication createSuccessAuthentication(UserDetails userDetails, Map<String, Object> map) { NextprotUserToken usrToken = new NextprotUserToken(); usrToken.setAuthenticated(true); usrToken.setPrincipal(userDetails); usrToken.setDetails(map); usrToken.getAuthorities().addAll(userDetails.getAuthorities()); return usrToken; } }