Commit 61577124 authored by Aman Verma's avatar Aman Verma
Browse files

Merge remote-tracking branch 'origin/master' into users/amaverma/implementInterfacesForAzure

parents b3eb9377 a6e2d3f0
This diff is collapsed.
......@@ -31,7 +31,7 @@
<groupId>org.opengroup.osdu</groupId>
<artifactId>os-schema</artifactId>
<version>0.10.0-SNAPSHOT</version>
<version>0.11.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>os-schema</name>
<description>os schema service </description>
......
......@@ -18,7 +18,7 @@
<parent>
<artifactId>os-schema</artifactId>
<groupId>org.opengroup.osdu</groupId>
<version>0.10.0-SNAPSHOT</version>
<version>0.11.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
......@@ -35,7 +35,7 @@
<dependency>
<groupId>org.opengroup.osdu</groupId>
<artifactId>os-schema-core</artifactId>
<version>0.10.0-SNAPSHOT</version>
<version>0.11.0-SNAPSHOT</version>
</dependency>
<!-- AWS managed packages -->
<dependency>
......@@ -67,7 +67,7 @@
<dependency>
<groupId>org.opengroup.osdu.core.aws</groupId>
<artifactId>os-core-lib-aws</artifactId>
<version>0.11.0-SNAPSHOT</version>
<version>0.11.0</version>
</dependency>
<dependency>
......
......@@ -18,21 +18,21 @@
<parent>
<artifactId>os-schema</artifactId>
<groupId>org.opengroup.osdu</groupId>
<version>0.10.0-SNAPSHOT</version>
<version>0.11.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>os-schema-azure</artifactId>
<version>0.10.0-SNAPSHOT</version>
<version>0.11.0-SNAPSHOT</version>
<description>Azure related implementation staff.</description>
<packaging>jar</packaging>
<properties>
<azure.version>2.1.7</azure.version>
<osdu.corelibazure.version>0.10.1</osdu.corelibazure.version>
<osdu.oscorecommon.version>0.11.0-rc4</osdu.oscorecommon.version>
<osdu.os-schema-core.version>0.10.0-SNAPSHOT</osdu.os-schema-core.version>
<osdu.corelibazure.version>0.11.0</osdu.corelibazure.version>
<osdu.oscorecommon.version>0.11.0</osdu.oscorecommon.version>
<osdu.os-schema-core.version>0.11.0-SNAPSHOT</osdu.os-schema-core.version>
<mockito.version>1.10.19</mockito.version>
<cucumber.version>5.4.0</cucumber.version>
<nimbus-jose-jwt-azure.version>8.20.2</nimbus-jose-jwt-azure.version>
......
......@@ -11,6 +11,10 @@ import java.util.Map;
@Component
public class AuthorizationServiceForServicePrincipalImpl implements IAuthorizationServiceForServicePrincipal {
private final String AAD_issuer_v1 = "https://sts.windows.net";
private final String AAD_issuer_v2 = "https://login.microsoftonline.com";
enum UserType {
REGULAR_USER,
GUEST_USER,
......@@ -26,14 +30,24 @@ public class AuthorizationServiceForServicePrincipalImpl implements IAuthorizati
}
final UserPrincipal userPrincipal = (UserPrincipal) principal;
String issuer = userPrincipal.getClaim("iss").toString();
UserType type = getType(userPrincipal);
if (type == UserType.SERVICE_PRINCIPAL) {
if (type == UserType.SERVICE_PRINCIPAL && issuedByAAD(issuer)) {
return true;
}
return false;
}
/***
* Check that issuer string startswith accepted prefix of AAD issuer url (V1 or V2).
* @param issuer claim for "issuer"
* @return true if issuer startswith V1 url or V2 url
*/
private boolean issuedByAAD(String issuer) {
return issuer.startsWith(AAD_issuer_v1) || issuer.startsWith(AAD_issuer_v2);
}
/**
* The internal method to get the user principal.
*
......
......@@ -15,7 +15,7 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
@ConditionalOnProperty(value = "azure.istio.auth.enabled", havingValue = "true", matchIfMissing = true)
public class AADSecurityConfigWithIstioEnabled extends WebSecurityConfigurerAdapter {
@Autowired
private AADAppRoleStatelessAuthenticationFilter appRoleAuthFilter;
private AzureIstioSecurityFilter azureIstioSecurityFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
......@@ -37,6 +37,6 @@ public class AADSecurityConfigWithIstioEnabled extends WebSecurityConfigurerAdap
"/webjars/**").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(appRoleAuthFilter, UsernamePasswordAuthenticationFilter.class);
.addFilterBefore(azureIstioSecurityFilter, UsernamePasswordAuthenticationFilter.class);
}
}
package org.opengroup.osdu.schema.security;
import com.azure.spring.autoconfigure.aad.UserPrincipal;
import com.nimbusds.jwt.JWTClaimsSet;
import net.minidev.json.JSONArray;
import org.opengroup.osdu.core.common.model.http.AppException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.ParseException;
import java.util.Base64;
import java.util.Collections;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import static org.springframework.util.StringUtils.hasText;
@Component
@ConditionalOnProperty(value = "azure.istio.auth.enabled", havingValue = "true", matchIfMissing = true)
public class AzureIstioSecurityFilter extends OncePerRequestFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(AzureIstioSecurityFilter.class);
private static final String X_ISTIO_CLAIMS_PAYLOAD = "x-payload";
private static final JSONArray DEFAULT_ROLE_CLAIM = new JSONArray().appendElement("USER");
private static final String ROLE_PREFIX = "ROLE_";
/**
* Filter logic.
* @param servletRequest Request object.
* @param servletResponse Response object.
* @param filterChain Filter Chain object.
* @throws IOException
* @throws ServletException
*/
@Override
protected void doFilterInternal(final HttpServletRequest servletRequest, final HttpServletResponse servletResponse, final FilterChain filterChain) throws ServletException, IOException {
final String istioPayload = servletRequest.getHeader(X_ISTIO_CLAIMS_PAYLOAD);
LOGGER.debug("Received headers list: {}", Collections.list(servletRequest.getHeaderNames()));
try {
if (hasText(istioPayload)) {
JWTClaimsSet claimsSet = JWTClaimsSet.parse(new String(Base64.getDecoder().decode(istioPayload)));
final JSONArray roles = Optional.ofNullable((JSONArray) claimsSet.getClaims().get("roles"))
.filter(r -> !r.isEmpty())
.orElse(DEFAULT_ROLE_CLAIM);
// By default the authenticated is set to true as part PreAuthenticatedAuthenticationToken constructor.
SecurityContextHolder
.getContext()
.setAuthentication(
new PreAuthenticatedAuthenticationToken(
new UserPrincipal(null,null, claimsSet),
null,
rolesToGrantedAuthorities(roles)
));
} else {
SecurityContextHolder
.getContext()
.setAuthentication(
new PreAuthenticatedAuthenticationToken(
null, null, null
));
}
} catch (ParseException ex) {
LOGGER.error("Failed to initialize UserPrincipal.", ex);
throw new AppException(500, "Unable to parse claims in istio payload", ex.getMessage());
}
try {
filterChain.doFilter(servletRequest, servletResponse);
} finally {
SecurityContextHolder.clearContext();
}
}
/**
* To return roles.
* @param roles Request Object.
* @return set representation of roles.
*/
protected Set<SimpleGrantedAuthority> rolesToGrantedAuthorities(final JSONArray roles) {
return roles.stream()
.filter(Objects::nonNull)
.map(s -> new SimpleGrantedAuthority(ROLE_PREFIX + s))
.collect(Collectors.toSet());
}
}
......@@ -21,9 +21,9 @@ AUTHORIZE_API_KEY=${entitlements_service_api_key}
# Azure AD configuration, commented below settings to disable AAD AuthN,
# Uncomment it In the Istio AUTHN disabled Scenario
azure.activedirectory.client-id=${aad_client_id}
azure.activedirectory.AppIdUri=api://${azure.activedirectory.client-id}
azure.activedirectory.session-stateless=true
# azure.activedirectory.client-id=${aad_client_id}
# azure.activedirectory.AppIdUri=api://${azure.activedirectory.client-id}
# azure.activedirectory.session-stateless=true
# Azure CosmosDB configuration
azure.cosmosdb.database=${cosmosdb_database}
......
package org.opengroup.osdu.schema.provider.azure.service.serviceimpl;
import com.azure.spring.autoconfigure.aad.UserPrincipal;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSObject;
import com.nimbusds.jose.Payload;
import com.nimbusds.jwt.JWTClaimsSet;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.impl.DefaultClaims;
import io.jsonwebtoken.impl.DefaultJws;
import lombok.Getter;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.opengroup.osdu.schema.azure.service.serviceimpl.AuthorizationServiceForServicePrincipalImpl;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class AuthorizationServiceForServicePrincipalImplTest {
@Mock
private Authentication auth;
@Mock
private SecurityContext securityContext;
@InjectMocks
private AuthorizationServiceForServicePrincipalImpl authorizationService;
@Before
public void setup() {
securityContext = Mockito.mock(SecurityContext.class);
auth = Mockito.mock(Authentication.class);
}
private UserPrincipal createAADUserPrincipal(String claimName, String claimValue, String issuer) {
final JWTClaimsSet jwtClaimsSet = new JWTClaimsSet.Builder()
//.subject("subject")
.claim(claimName, claimValue)
.issuer(issuer)
.build();
final JWSObject jwsObject = new JWSObject(new JWSHeader.Builder(JWSAlgorithm.RS256).build(),
new Payload(jwtClaimsSet.toString()));
return new UserPrincipal("token", jwsObject, jwtClaimsSet);
}
private DummyAuthToken createSAuthToken(final String email, final String appcode) {
final Map<String, Object> map = new HashMap<>();
map.put("email", email);
map.put("appcode", appcode);
map.put("iss", "sauth-preview.slb.com");
Jws<Claims> jws = new DefaultJws<>(null, new DefaultClaims(map), null);
return new DummyAuthToken(jws);
}
private void createSAuthTokenSetSecurityContext(final String email, final String appcode) {
DummyAuthToken dummyAuthToken = createSAuthToken(email, appcode);
SecurityContextHolder.setContext(securityContext);
when(securityContext.getAuthentication()).thenReturn(auth);
when(auth.getPrincipal()).thenReturn(dummyAuthToken);
}
private UserPrincipal createAADUserPrincipalSetSecurityContext(String claimName, String claimValue, String issuer) {
UserPrincipal dummyAADPrincipal = createAADUserPrincipal(claimName, claimValue, issuer);
SecurityContextHolder.setContext(securityContext);
when(securityContext.getAuthentication()).thenReturn(auth);
when(auth.getPrincipal()).thenReturn(dummyAADPrincipal);
return dummyAADPrincipal;
}
@Test
public void shouldReturnFalseWhenSAuthTokenIsSetInContext() {
createSAuthTokenSetSecurityContext("email", null);
assertFalse(authorizationService.isDomainAdminServiceAccount());
}
@Test
public void shouldReturnTrueWhenAADTokenIsSetInContext_AndIssuerIsAAD() {
createAADUserPrincipalSetSecurityContext(TestUtils.APPID, TestUtils.getAppId(), TestUtils.getAadIssuer());
assertTrue(authorizationService.isDomainAdminServiceAccount());
}
@Test
public void shouldReturnTrueWhenAADTokenIsSetInContext_AndIssuerIsAADV2() {
createAADUserPrincipalSetSecurityContext(TestUtils.APPID, TestUtils.getAppId(), TestUtils.getAadIssuerV2());
assertTrue(authorizationService.isDomainAdminServiceAccount());
}
@Test
public void shouldReturnFalseWhenAADTokenIsSetInContext_AndIssuerIsNotAAD() {
createAADUserPrincipalSetSecurityContext(TestUtils.APPID, TestUtils.getAppId(), TestUtils.getNonAadIssuer());
assertFalse(authorizationService.isDomainAdminServiceAccount());
}
@Getter
public class DummyAuthToken {
private final Jws<Claims> jws;
public DummyAuthToken(Jws<Claims> jws) {
this.jws = jws;
}
public <T> T getClaim(String claim, Class<T> type) {
return jws.getBody().get(claim, type);
}
public String getIssuer() {
return jws.getBody().getIssuer();
}
}
}
package org.opengroup.osdu.schema.provider.azure.service.serviceimpl;
public class TestUtils {
private static final String appId = "1234";
public static final String APPID = "appid";
public static final String aadIssuer = "https://sts.windows.net";
public static final String aadIssuerV2 = "https://login.microsoftonline.com";
public static final String nonAadIssuer = "https://login.abc.com";
public static String getAppId() {return appId;}
public static String getAadIssuer() {return aadIssuer;}
public static String getAadIssuerV2() {return aadIssuerV2;}
public static String getNonAadIssuer() {return nonAadIssuer;}
}
......@@ -3,7 +3,7 @@
<parent>
<groupId>org.opengroup.osdu</groupId>
<artifactId>os-schema</artifactId>
<version>0.10.0-SNAPSHOT</version>
<version>0.11.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
......@@ -29,7 +29,7 @@
<dependency>
<groupId>org.opengroup.osdu</groupId>
<artifactId>os-schema-core</artifactId>
<version>0.10.0-SNAPSHOT</version>
<version>0.11.0-SNAPSHOT</version>
</dependency>
<dependency>
......
......@@ -3,7 +3,7 @@
<parent>
<groupId>org.opengroup.osdu</groupId>
<artifactId>os-schema</artifactId>
<version>0.10.0-SNAPSHOT</version>
<version>0.11.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>os-schema-ibm</artifactId>
......@@ -21,7 +21,7 @@
<dependency>
<groupId>org.opengroup.osdu</groupId>
<artifactId>os-schema-core</artifactId>
<version>0.10.0-SNAPSHOT</version>
<version>0.11.0-SNAPSHOT</version>
</dependency>
<dependency>
......
......@@ -3,7 +3,7 @@
<parent>
<groupId>org.opengroup.osdu</groupId>
<artifactId>os-schema</artifactId>
<version>0.10.0-SNAPSHOT</version>
<version>0.11.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
......@@ -13,7 +13,7 @@
<properties>
<springfox-version>2.7.0</springfox-version>
<os-core-common.version>0.11.0-rc4</os-core-common.version>
<os-core-common.version>0.11.0</os-core-common.version>
</properties>
<dependencies>
......
......@@ -3,7 +3,7 @@
<groupId>org.opengroup.osdu</groupId>
<artifactId>os-schema-test</artifactId>
<version>0.10.0-SNAPSHOT</version>
<version>0.11.0-SNAPSHOT</version>
<description>Schema Service Integration Test Root Project</description>
<packaging>pom</packaging>
......
......@@ -4,7 +4,7 @@
<parent>
<groupId>org.opengroup.osdu</groupId>
<artifactId>os-schema-test</artifactId>
<version>0.10.0-SNAPSHOT</version>
<version>0.11.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
......
......@@ -4,7 +4,7 @@
<parent>
<groupId>org.opengroup.osdu</groupId>
<artifactId>os-schema-test</artifactId>
<version>0.10.0-SNAPSHOT</version>
<version>0.11.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
......
......@@ -4,13 +4,13 @@
<parent>
<groupId>org.opengroup.osdu</groupId>
<artifactId>os-schema-test</artifactId>
<version>0.10.0-SNAPSHOT</version>
<version>0.11.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>org.opengroup.osdu</groupId>
<artifactId>os-schema-test-gcp</artifactId>
<version>0.10.0-SNAPSHOT</version>
<version>0.11.0-SNAPSHOT</version>
<packaging>jar</packaging>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment