Commit f61c2251 authored by Vibhuti Sharma [Microsoft]'s avatar Vibhuti Sharma [Microsoft]
Browse files

Merge branch 'users/Vibhuti/authN' into 'master'

Using Istio auth in Partition Service

See merge request !83
parents 57ee2f0c d85b8344
Pipeline #61448 failed with stages
in 29 minutes and 16 seconds
......@@ -17,7 +17,7 @@ The following software have components provided under the terms of this license:
- Apache Commons CLI (from http://commons.apache.org/proper/commons-cli/)
- Cobertura (from http://cobertura.sourceforge.net)
- Default Plexus Container (from https://repo1.maven.org/maven2/org/codehaus/plexus/plexus-container-default)
- Plexus Common Utilities (from http://plexus.codehaus.org/plexus-utils)
- Plexus Common Utilities (from https://repo1.maven.org/maven2/org/codehaus/plexus/plexus-utils)
- oro (from )
========================================================================
......@@ -380,14 +380,14 @@ The following software have components provided under the terms of this license:
- Jackson datatype: Joda (from https://github.com/FasterXML/jackson-datatype-joda)
- Jackson datatype: jdk8 (from https://repo1.maven.org/maven2/com/fasterxml/jackson/datatype/jackson-datatype-jdk8)
- Jackson extensions to the Google HTTP Client Library for Java. (from https://repo1.maven.org/maven2/com/google/http-client/google-http-client-jackson)
- Jackson module: JAXB Annotations (from https://github.com/FasterXML/jackson-modules-base)
- Jackson module: Afterburner (from https://github.com/FasterXML/jackson-modules-base)
- Jackson module: Old JAXB Annotations (javax.xml.bind) (from https://github.com/FasterXML/jackson-modules-base)
- Jackson-annotations (from http://github.com/FasterXML/jackson)
- Jackson-annotations (from http://github.com/FasterXML/jackson)
- Jackson-core (from https://github.com/FasterXML/jackson-core)
- Jackson-core (from https://github.com/FasterXML/jackson-core)
- Jackson-dataformat-XML (from https://github.com/FasterXML/jackson-dataformat-xml)
- Jackson-dataformat-YAML (from https://github.com/FasterXML/jackson-dataformats-text)
- Jackson-module-Afterburner (from http://wiki.fasterxml.com/JacksonHome)
- Jackson-module-parameter-names (from https://repo1.maven.org/maven2/com/fasterxml/jackson/module/jackson-module-parameter-names)
- Jakarta Bean Validation API (from https://beanvalidation.org)
- Jakarta Expression Language Implementation (from https://projects.eclipse.org/projects/ee4j.el)
......@@ -483,7 +483,7 @@ The following software have components provided under the terms of this license:
- OpenCensus (from https://github.com/census-instrumentation/opencensus-java)
- OpenCensus (from https://github.com/census-instrumentation/opencensus-java)
- PWDB :: Database (from https://repo1.maven.org/maven2/org/linguafranca/pwdb/database)
- Plexus Common Utilities (from http://plexus.codehaus.org/plexus-utils)
- Plexus Common Utilities (from https://repo1.maven.org/maven2/org/codehaus/plexus/plexus-utils)
- Plexus Velocity Component (from )
- PowerMock (from http://www.powermock.org)
- PowerMock (from http://www.powermock.org)
......@@ -630,7 +630,7 @@ The following software have components provided under the terms of this license:
- Hamcrest (from http://hamcrest.org/JavaHamcrest/)
- Hamcrest Core (from http://hamcrest.org/)
- HdrHistogram (from http://hdrhistogram.github.io/HdrHistogram/)
- Plexus Common Utilities (from http://plexus.codehaus.org/plexus-utils)
- Plexus Common Utilities (from https://repo1.maven.org/maven2/org/codehaus/plexus/plexus-utils)
- Reflections (from http://github.com/ronmamo/reflections)
- Stax2 API (from http://github.com/FasterXML/stax2-api)
- ThreeTen backport (from https://www.threeten.org/threetenbp)
......@@ -664,7 +664,7 @@ The following software have components provided under the terms of this license:
- Microsoft Application Insights Java SDK Web Module (from https://github.com/Microsoft/ApplicationInsights-Java)
- Microsoft Application Insights Log4j 2 Appender (from https://github.com/Microsoft/ApplicationInsights-Java)
- Netty/Codec/HTTP (from https://repo1.maven.org/maven2/io/netty/netty-codec-http)
- Plexus Common Utilities (from http://plexus.codehaus.org/plexus-utils)
- Plexus Common Utilities (from https://repo1.maven.org/maven2/org/codehaus/plexus/plexus-utils)
- Protocol Buffers [Core] (from https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java)
- Protocol Buffers [Util] (from https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java-util)
- Reflections (from http://github.com/ronmamo/reflections)
......@@ -965,7 +965,7 @@ Public-Domain
========================================================================
The following software have components provided under the terms of this license:
- Plexus Common Utilities (from http://plexus.codehaus.org/plexus-utils)
- Plexus Common Utilities (from https://repo1.maven.org/maven2/org/codehaus/plexus/plexus-utils)
- Spongy Castle (from http://rtyley.github.io/spongycastle/)
========================================================================
......
......@@ -94,3 +94,5 @@ spec:
value: "api://$(aad_client_id)"
- name: azure_activedirectory_session_stateless
value: "true"
- name: azure_istioauth_enabled
value: "true"
\ No newline at end of file
......@@ -16,6 +16,7 @@ package org.opengroup.osdu.partition.provider.azure.security;
import com.azure.spring.autoconfigure.aad.AADAppRoleStatelessAuthenticationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.HttpStatus;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
......@@ -27,6 +28,7 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@ConditionalOnProperty(value = "azure.istio.auth.enabled", havingValue = "false", matchIfMissing = false)
public class AADSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
......
package org.opengroup.osdu.partition.provider.azure.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@ConditionalOnProperty(value = "azure.istio.auth.enabled", havingValue = "true", matchIfMissing = true)
public class AzureIstioSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private AzureIstioSecurityFilter appRoleAuthFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().disable()
.csrf().disable()
.addFilterBefore(appRoleAuthFilter, UsernamePasswordAuthenticationFilter.class);
}
}
package org.opengroup.osdu.partition.provider.azure.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.*;
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());
}
}
......@@ -25,6 +25,9 @@ import java.util.Map;
@Component
public class AuthorizationService implements IAuthorizationService {
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,
......@@ -40,14 +43,24 @@ public class AuthorizationService implements IAuthorizationService {
}
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.
*
......
# Copyright © Microsoft Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
runtime.env.local=true
azure.activedirectory.client-id=${aad_client_id}
azure.activedirectory.AppIdUri=api://${azure.activedirectory.client-id}
azure.activedirectory.session-stateless=true
# Istio Auth Enabled
azure.istio.auth.enabled=false
......@@ -11,10 +11,16 @@ logging.slf4jlogger.enabled=true
logging.mdccontext.enabled=true
# AAD properties
# Azure AD configuration, commented below settings to disable AAD AuthN,
# Uncomment it in the Istio AUTHN disabled Scenario
#azure.activedirectory.AppIdUri=api://${azure.activedirectory.client-id}
#azure.activedirectory.session-stateless=true
azure.activedirectory.app-resource-id=${aad_client_id}
azure.activedirectory.client-id=${aad_client_id}
azure.activedirectory.AppIdUri=api://${azure.activedirectory.client-id}
azure.activedirectory.session-stateless=true
# Istio
azure.istio.auth.enabled=${azure_istioauth_enabled}
# Azure KeyVault configuration
azure.keyvault.url=${KEYVAULT_URI}
......
......@@ -34,7 +34,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {HomeController.class,
@SpringBootTest(properties = {"azure.istio.auth.enabled=false"}, classes = {HomeController.class,
PartitionApi.class,
AADSecurityConfig.class,
AADAppRoleStatelessAuthenticationFilter.class})
......
......@@ -39,7 +39,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@RunWith(SpringRunner.class)
@PrepareForTest(SecurityContextHolder.class)
@SpringBootTest(classes = {WhoamiController.class, AADSecurityConfig.class,
@SpringBootTest(properties = {"azure.istio.auth.enabled=false"}, classes = {WhoamiController.class, AADSecurityConfig.class,
AADAppRoleStatelessAuthenticationFilter.class})
@WebAppConfiguration
public class WhoamiControllerTest {
......
......@@ -103,11 +103,23 @@ public class AuthorizationServiceTest {
}
@Test
public void shouldReturnTrueWhenAADTokenIsSetInContext() {
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 {
......
......@@ -18,7 +18,11 @@ 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;}
}
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