Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Op 17001 audit tail exec v4.0 phase2 #239

Merged
merged 30 commits into from
Aug 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a22ee35
OP-15420: filterBy in gate v4.0
arunkumaropsmx May 30, 2022
098c31d
Merge pull request #215 from OpsMx/Op-15420-v4.0
ramyaravi-opsmx May 30, 2022
c9aeffe
OP-14834: invalidate session and throw SAMLAuthenticationException (#…
rahul-chekuri Jun 9, 2022
a64dfcd
OP-16308: OP-16308: Wait and retry if connection fails. Also, css fil…
rahul-chekuri Jun 22, 2022
6ad892d
op-16538 op-16537 - Added autocomplete off in login page
Jul 4, 2022
5b3530a
Merge pull request #223 from OpsMx/feature/op-16538-op-16537-autoComp…
Luthan95 Jul 4, 2022
f05e3a3
OP-16545: jquery upgraded to 3.6.0. (#224)
rahul-chekuri Jul 29, 2022
c77a81d
OP-16992 : Added parameter for PipelineAndPolicy summarycount (#229) …
sudhakaropsmx Aug 5, 2022
131832d
OP-16541: Added contentSecurityPolicy header.
rahul-chekuri Aug 8, 2022
c214856
OP-16541: config change contentSecurityPolicy.
rahul-chekuri Aug 8, 2022
a62667a
Merge pull request #231 from OpsMx/bugfix/OP-16541-4-0-csp
sriharshakancharla Aug 8, 2022
97a4a44
OP-17106: Added SamlSsoEventPublishConfig to update ApplicationEventP…
rahul-chekuri Aug 10, 2022
4e15c26
OP-17106: get FilterChainProxy and then go for SAMLProcessingFilter t…
rahul-chekuri Aug 10, 2022
18ddb81
OP-17106: code correction.
rahul-chekuri Aug 10, 2022
7d495c4
OP-17106: added logs.
rahul-chekuri Aug 10, 2022
658e6e1
OP-17106: Handling InteractiveAuthenticationSuccessEvent events also.
rahul-chekuri Aug 10, 2022
1cf9ba7
OP-17106: Handling serialization issues.
rahul-chekuri Aug 10, 2022
7ba6f9a
OP-17106: set details to null to remove some json serialization issues.
rahul-chekuri Aug 11, 2022
fdad506
OP-17106: Added AuditData.
rahul-chekuri Aug 11, 2022
0f7cdeb
OP-17106: Setting name.
rahul-chekuri Aug 11, 2022
a9a599f
OP-17106: Setting name via source.
rahul-chekuri Aug 11, 2022
6001251
OP-17106: Refactored code.
rahul-chekuri Aug 11, 2022
6f60e49
OP-17106: Added some comments.
rahul-chekuri Aug 11, 2022
0990e9f
OP-17106: Refactored configs.
rahul-chekuri Aug 11, 2022
9a119d0
Merge pull request #234 from OpsMx/bugfix/OP-17106-4-0
ramyaravi-opsmx Aug 12, 2022
e4b4977
OP-17106: Appending roles configs.
rahul-chekuri Aug 12, 2022
334e9a0
OP-17106: Logs and comments.
rahul-chekuri Aug 12, 2022
df4d146
Merge pull request #235 from OpsMx/bugfix/OP-17106-4-0
ramyaravi-opsmx Aug 12, 2022
95be4c1
OP-17001: audit trail execution (#237)
ramyaravi-opsmx Aug 12, 2022
da4e830
OP-17001: audit trail execution phase 3
ramyaravi-opsmx Aug 12, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions gate-core/gate-core.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ dependencies {
implementation "org.apache.commons:commons-lang3"
implementation group: 'io.jsonwebtoken', name: 'jjwt', version: '0.9.1'
implementation group: 'org.springframework.cloud', name: 'spring-cloud-starter-openfeign', version: '2.2.4.RELEASE'
compile group: 'org.springframework.retry', name: 'spring-retry', version: '1.2.2.RELEASE'
}

sourceSets {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ class AuthConfig {
@Value('${allowUnauthenticatedAccess.webhooks:false}')
boolean isSpinnakerWebhooksUnauthenticatedAccessEnabled

@Value('${security.contentSecurityPolicy:\'object-src \'none\'; script-src \'unsafe-eval\' \'unsafe-inline\' https: http:;\'}')
String contentSecurityPolicy

void configure(HttpSecurity http) throws Exception {
// @formatter:off
if(isAgentAPIUnauthenticatedAccessEnabled && isSpinnakerWebhooksUnauthenticatedAccessEnabled){
Expand Down Expand Up @@ -330,6 +333,8 @@ class AuthConfig {
http.authorizeRequests().antMatchers(HttpMethod.POST, '/webhooks/**').authenticated()
}

http.headers().contentSecurityPolicy(contentSecurityPolicy)

http.logout()
.logoutUrl("/auth/logout")
.logoutSuccessHandler(permissionRevokingLogoutSuccessHandler)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.netflix.spinnaker.fiat.model.resources.Role
import com.netflix.spinnaker.fiat.shared.FiatPermissionEvaluator
import com.netflix.spinnaker.fiat.shared.FiatService
import com.netflix.spinnaker.fiat.shared.FiatStatus
import com.netflix.spinnaker.gate.retrofit.UpstreamBadRequest
import com.netflix.spinnaker.gate.security.SpinnakerUser
import com.netflix.spinnaker.gate.services.internal.ExtendedFiatService
import com.netflix.spinnaker.kork.core.RetrySupport
Expand All @@ -42,6 +43,8 @@ import javax.annotation.Nonnull
import java.time.Duration

import static com.netflix.spinnaker.gate.retrofit.UpstreamBadRequest.classifyError
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;

@Slf4j
@Component
Expand Down Expand Up @@ -90,6 +93,8 @@ class PermissionService {
}
}


@Retryable(value = UpstreamBadRequest.class, maxAttempts = 3, backoff = @Backoff(delay = 4000l))
void loginWithRoles(String userId, Collection<String> roles) {
if (fiatStatus.isEnabled()) {
try {
Expand All @@ -98,6 +103,7 @@ class PermissionService {
permissionEvaluator.invalidatePermission(userId)
})
} catch (RetrofitError e) {
log.error("Exception caught while updating the roles. Will wait and retry: {}" , e)
throw classifyError(e)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import com.netflix.spinnaker.gate.security.SpinnakerAuthConfig
import com.netflix.spinnaker.gate.services.PermissionService
import com.netflix.spinnaker.kork.core.RetrySupport
import com.netflix.spinnaker.security.User
import com.opsmx.spinnaker.gate.security.saml.SamlAuthTokenUpdateFilter
import groovy.util.logging.Slf4j
import org.opensaml.saml2.core.Assertion
import org.opensaml.saml2.core.Attribute
Expand All @@ -43,11 +44,12 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.core.userdetails.UsernameNotFoundException
import org.springframework.security.extensions.saml2.config.SAMLConfigurer
import org.springframework.security.saml.websso.WebSSOProfileConsumerImpl
import org.springframework.security.saml.SAMLCredential
import org.springframework.security.saml.userdetails.SAMLUserDetailsService
import org.springframework.security.saml.websso.WebSSOProfileConsumerImpl
import org.springframework.security.web.authentication.RememberMeServices
import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter
import org.springframework.session.web.http.DefaultCookieSerializer
import org.springframework.stereotype.Component

Expand Down Expand Up @@ -168,7 +170,9 @@ class SamlSsoConfig extends WebSecurityConfigurerAdapter {
.keyPassword(samlSecurityConfigProperties.keyStorePassword)

saml.init(http)

SamlAuthTokenUpdateFilter authTokenUpdateFilter = new SamlAuthTokenUpdateFilter()
http.addFilterAfter(authTokenUpdateFilter,
BasicAuthenticationFilter.class)
// @formatter:on

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.opsmx.spinnaker.gate.security.saml;

import org.springframework.security.core.AuthenticationException;

public class SAMLAuthenticationException extends AuthenticationException {
public SAMLAuthenticationException(String msg) {
super(msg);
}

public SAMLAuthenticationException(String msg, Throwable t) {
super(msg, t);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright 2022 OpsMx, Inc.
*
* 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.
*/

package com.opsmx.spinnaker.gate.security.saml;

import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.providers.ExpiringUsernameAuthenticationToken;
import org.springframework.web.filter.GenericFilterBean;

public class SamlAuthTokenUpdateFilter extends GenericFilterBean {

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
logger.debug("SamlAuthTokenUpdateFilter doFilter started");
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

logger.debug("Previously Authenticated is : " + authentication);
if (authentication instanceof ExpiringUsernameAuthenticationToken
&& !authentication.isAuthenticated()) {
if (logger.isDebugEnabled()) {
logger.debug(
"Previously Authenticated token Expired; redirecting to authentication entry point.");
}

HttpSession session = request.getSession();
if (session != null) {
session.invalidate();
}
throw new SAMLAuthenticationException("Previously Authenticated token Expired");
}
logger.debug("SamlAuthTokenUpdateFilter doFilter ended");

chain.doFilter(request, response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.opsmx.spinnaker.gate.security.saml;

import java.util.ArrayList;
import java.util.List;
import javax.servlet.Filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.saml.SAMLProcessingFilter;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.SecurityFilterChain;

@ConditionalOnExpression("${saml.enabled:false}")
@Configuration
@Slf4j
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SamlSsoEventPublishConfig {

private ApplicationEventPublisher applicationEventPublisher;

@Autowired
@Qualifier("springSecurityFilterChain")
private Filter springSecurityFilterChain;

@Autowired
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}

@Bean
public FilterChainProxy getFilters() {
FilterChainProxy filterChainProxy = (FilterChainProxy) springSecurityFilterChain;
List<SecurityFilterChain> list = filterChainProxy.getFilterChains();

list.stream()
.flatMap(chain -> chain.getFilters().stream())
.filter(filter -> filter.getClass() == FilterChainProxy.class)
.findAny()
.map(FilterChainProxy.class::cast)
.map(FilterChainProxy::getFilterChains)
.orElse(new ArrayList<>())
.stream()
.flatMap(chin -> chin.getFilters().stream())
.filter(filter -> filter.getClass() == SAMLProcessingFilter.class)
.findAny()
.map(SAMLProcessingFilter.class::cast)
.ifPresent(filter -> filter.setApplicationEventPublisher(applicationEventPublisher));
return filterChainProxy;
}
}
1 change: 1 addition & 0 deletions gate-web/config/gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ spring:
profiles: googleOAuth

security:
contentSecurityPolicy: "object-src 'none'; script-src 'unsafe-eval' 'unsafe-inline' https: http:;"
oauth2:
client:
# Set these values in your own config file (e.g. spinnaker-local.yml or gate-googleOAuth.yml).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,23 @@ class OpsmxAutopilotController {
return opsmxAutopilotService.getAutoResponse9(type, source, source1, source2, source3, source4, source5, source6, source7, source8, imageId)
}

@ApiOperation(value = "Endpoint for autopilot rest services")
@RequestMapping(value = "/{type}/{source}/{source1}/{source2}/{source3}/{source4}/{source5}/{source6}", method = RequestMethod.GET)
Object getAutoResponse10(@PathVariable("type") String type,
@PathVariable("source") String source,
@PathVariable("source1") String source1,
@PathVariable("source2") String source2,
@PathVariable("source3") String source3,
@PathVariable("source4") String source4,
@PathVariable("source5") String source5,
@PathVariable("source6") String source6,
@RequestParam(value = "imageId", required = false) String imageId,
@RequestParam(value = "canaryIds", required = false) String canaryIds,
@RequestParam(value = "gateIds", required = false) String gateIds) {

return opsmxAutopilotService.getAutoResponse10(type, source, source1, source2, source3, source4, source5, source6,imageId, canaryIds, gateIds)
}

@ApiOperation(value = "Endpoint for autopilot rest services")
@RequestMapping(value = "/{type}", method = RequestMethod.DELETE)
Object deleteAutoResponse1(@PathVariable("type") String type) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,23 @@ class OpsmxDashboardController {
return opsmxDashboardService.getDashboardResponse9(version, type, source, source1, source2, source3, source4, source5, source6)
}


@ApiOperation(value = "Endpoint for dashboard rest services")
@RequestMapping(value = "/{version}/{type}/{source}/{source1}/{source2}/{source3}/{source4}/{source5}/{source6}/{source7}", method = RequestMethod.GET)
Object getDashboardResponse10(@PathVariable("version") String version,
@PathVariable("type") String type,
@PathVariable("source") String source,
@PathVariable("source1") String source1,
@PathVariable("source2") String source2,
@PathVariable("source3") String source3,
@PathVariable("source4") String source4,
@PathVariable("source5") String source5,
@PathVariable("source6") String source6,
@PathVariable("source7") String source7) {

return opsmxDashboardService.getDashboardResponse10(version, type, source, source1, source2, source3, source4, source5, source6,source7)
}

@ApiOperation(value = "Endpoint for dashboard rest services")
@RequestMapping(value = "/{version}/{type}", method = RequestMethod.DELETE)
Object deleteDashboardResponse(@PathVariable("version") String version,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -503,9 +503,11 @@ class OpsmxOesController {
@PathVariable("source2") String source2,
@PathVariable("source3") String source3,
@PathVariable("source4") String source4,
@PathVariable("source5") String source5) {
@PathVariable("source5") String source5,
@RequestParam(value = "gateIds", required = false) String gateIds
) {

return opsmxOesService.getOesResponse8(type, source, source1, source2, source3, source4, source5)
return opsmxOesService.getOesResponse8(type, source, source1, source2, source3, source4, source5,gateIds)
}

@ApiOperation(value = "Endpoint for Oes rest services")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,9 @@ class OpsmxPlatformController {
@RequestParam(value = "sortOrder", required = false) String sortOrder,
@RequestParam(value = "applicationId", required = false) Integer applicationId,
@RequestParam(value = "applicationName", required = false) String applicationName,
@RequestParam(value = "noOfDays", required = false) Integer noOfDays) {
return opsmxPlatformService.getPlatformResponse1(version, type, datasourceType, accountName, source, permission, search, username, pageNo, pageLimit, sortBy, sortOrder, applicationId, applicationName, noOfDays)
@RequestParam(value = "noOfDays", required = false) Integer noOfDays,
@RequestParam(value = "filterBy", required = false) String filterBy) {
return opsmxPlatformService.getPlatformResponse1(version, type, datasourceType, accountName, source, permission, search, username, pageNo, pageLimit, sortBy, sortOrder, applicationId, applicationName, noOfDays, filterBy)
}

@ApiOperation(value = "Endpoint for platform rest services")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ interface OpsmxAutopilotService {
@Query("canaryIds") String canaryIds,
@Query("gateIds") String gateIds)


@GET("/autopilot/{type}/{source}/{source1}/{source2}/{source3}/{source4}/{source5}/{source6}/{source7}/{source8}")
Object getAutoResponse9(@Path('type') String type,
@Path('source') String source,
Expand All @@ -173,6 +174,19 @@ interface OpsmxAutopilotService {
@Path('source8') String source8,
@Query("imageId") String imageId)

@GET("/autopilot/{type}/{source}/{source1}/{source2}/{source3}/{source4}/{source5}/{source6}")
Object getAutoResponse10(@Path('type') String type,
@Path('source') String source,
@Path('source1') String source1,
@Path('source2') String source2,
@Path('source3') String source3,
@Path('source4') String source4,
@Path('source5') String source5,
@Path('source6') String source6,
@Query("imageId") String imageId,
@Query("canaryIds") String canaryIds,
@Query("gateIds") String gateIds)

@DELETE("/autopilot/{type}")
Object deleteAutoResponse1(@Path('type') String type)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,18 @@ interface OpsmxDashboardService {
@Path('source5') String source5,
@Path('source6') String source6)

@GET("/dashboardservice/{version}/{type}/{source}/{source1}/{source2}/{source3}/{source4}/{source5}/{source6}/{source7}")
Object getDashboardResponse10(@Path('version') String version,
@Path('type') String type,
@Path('source') String source,
@Path('source1') String source1,
@Path('source2') String source2,
@Path('source3') String source3,
@Path('source4') String source4,
@Path('source5') String source5,
@Path('source6') String source6,
@Path('source7') String source7)

@DELETE("/dashboardservice/{version}/{type}")
Object deleteDashboardResponse(@Path('version') String version,
@Path('type') String type)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ interface OpsmxOesService {
@Path('source2') String source2,
@Path('source3') String source3,
@Path('source4') String source4,
@Path('source5') String source5)
@Path('source5') String source5,
@Query("gateIds") String gateIds)

@GET("/oes/{type}/{source}/{source1}/{source2}/{source3}/{source4}/{source5}/{source6}")
Object getOesResponse9(@Path('type') String type,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ interface OpsmxPlatformService {
@Query("sortOrder") String sortOrder,
@Query("applicationId") Integer applicationId,
@Query("applicationName") String applicationName,
@Query("noOfDays") Integer noOfDays)
@Query("noOfDays") Integer noOfDays,
@Query("filterBy") String filterBy)

@GET("/platformservice/{version}/{type}/{source}")
Object getPlatformResponse(@Path('version') String version,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,10 @@ class OpsmxAuditClientServiceController {
@PathVariable("type") String type,
@PathVariable("source") String source,
@PathVariable("source1") String source1,
@PathVariable("source2") String source2) {
@PathVariable("source2") String source2,
@RequestParam(value = "noOfDays", required = false) String noOfDays) {

return opsmxAuditClientService.getAuditClientResponse4(version, type, source, source1, source2)
return opsmxAuditClientService.getAuditClientResponse4(version, type, source, source1, source2, noOfDays)
}

@ApiOperation(value = "Endpoint for audit-client rest services")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ interface OpsmxAuditClientService {
@Path('type') String type,
@Path('source') String source,
@Path('source1') String source1,
@Path('source2') String source2)
@Path('source2') String source2,
@Query("noOfDays") String noOfDays)

@GET("/auditclientservice/{version}/{type}/{source}/{source1}/{source2}/{source3}")
Object getAuditClientResponse5(@Path('version') String version,
Expand Down
Loading