Skip to content

Commit

Permalink
Feature visibility and Application Id RBAC auth logic added
Browse files Browse the repository at this point in the history
  • Loading branch information
Pranav-b-7 committed Feb 15, 2022
1 parent 69b392f commit c87e2a0
Show file tree
Hide file tree
Showing 9 changed files with 542 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ package com.netflix.spinnaker.gate.services
import org.springframework.cloud.openfeign.FeignClient
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestHeader
Expand All @@ -16,4 +18,10 @@ interface OesAuthorizationService {
@PutMapping(value = "/platformservice/v2/usergroups/importAndCache", produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity<Object> cacheUserGroups(@RequestBody Collection<String> data, @RequestHeader(value = "x-spinnaker-user") String userName)

@GetMapping(value = "/platformservice/v6/users/{username}/features/{featureType}", produces = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity<Map<String, String>> isFeatureVisibility(@PathVariable("username") String username, @PathVariable("featureType") String featureType, @RequestHeader(value = "x-spinnaker-user") String userName)

@GetMapping(value = "/platformservice/v6/users/{username}/features/{featureType}/{resourceId}", produces = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity<List<String>> fetchPermissions(@PathVariable("username") String username, @PathVariable("featureType") String featureType, @PathVariable("resourceId") Integer resourceId, @RequestHeader(value = "x-spinnaker-user") String userName)

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ import com.netflix.spinnaker.gate.interceptors.RequestIdInterceptor
import com.netflix.spinnaker.gate.retrofit.UpstreamBadRequest
import com.netflix.spinnaker.kork.dynamicconfig.DynamicConfigService
import com.netflix.spinnaker.kork.web.interceptors.MetricsInterceptor
import com.opsmx.spinnaker.gate.interceptors.ApplicationIdRbacInterceptor
import com.opsmx.spinnaker.gate.interceptors.OesServiceInterceptor
import com.opsmx.spinnaker.gate.interceptors.FeatureVisibilityRbacInterceptor
import com.opsmx.spinnaker.gate.rbac.ApplicationFeatureRbac
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.ApplicationContext
Expand Down Expand Up @@ -60,6 +63,12 @@ public class GateWebConfig implements WebMvcConfigurer {
@Value('${rate-limit.learning:true}')
Boolean rateLimitLearningMode

@Autowired
FeatureVisibilityRbacInterceptor featureVisibilityRbacInterceptor

@Autowired
ApplicationIdRbacInterceptor applicationIdRbacInterceptor



@Override
Expand All @@ -77,6 +86,10 @@ public class GateWebConfig implements WebMvcConfigurer {
oesServicePathPatterns.add("/datasource/cache/save")
oesServicePathPatterns.add("/datasource/cache/evict")
registry.addInterceptor(new OesServiceInterceptor()).addPathPatterns(oesServicePathPatterns)

registry.addInterceptor(featureVisibilityRbacInterceptor).addPathPatterns(ApplicationFeatureRbac.applicationFeatureRbacEndpoints).order(1)
registry.addInterceptor(applicationIdRbacInterceptor).addPathPatterns(ApplicationFeatureRbac.endpointsWithApplicationId).order(2)

}

@Bean
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* 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.enums;

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

public enum PermissionEnum {
view("view a feature"),
create_or_edit("create or edit a feature"),
delete("delete a feature"),
runtime_access("execute (trigger custom gate)"),
approve_gate("approve a visibility gate");

public String description;

public String getDescription() {
return this.description;
}

private PermissionEnum(String description) {
this.description = description;
}

public static PermissionEnum getPermissionEnum(String permissionId) {
return Arrays.stream(PermissionEnum.values())
.filter(permission -> permission.name().equals(permissionId))
.findFirst()
.orElse(null);
}

public static List<PermissionEnum> getPermissionEnumsByValues(String[] values) {
return Arrays.stream(values)
.map(val -> PermissionEnum.getPermissionEnum(val))
.collect(Collectors.toList());
}

public static String getPermissionEnumDisplayName(PermissionEnum permissionId) {
String displayName = "";
switch (permissionId) {
case view:
displayName = "View";
break;
case create_or_edit:
displayName = "Create/Edit";
break;
case delete:
displayName = "Delete";
break;
case runtime_access:
displayName = "Runtime Access";
break;
case approve_gate:
displayName = "Approval Gate";
break;
}
return displayName;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* 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.enums;

public enum RbacFeatureType {
APP("Application"),
AGENT("Agent"),
AUDIT("Audit"),
APPROVAL_GATE("Approval Gate"),
CLOUD_PROVIDER("Cloud Provider"),
INTEGRATION("Integration"),
POLICY("Policy");

public String description;

public String getDescription() {
return this.description;
}

private RbacFeatureType(String description) {
this.description = description;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2022 Netflix, 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.exception;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@Slf4j
@ResponseStatus(HttpStatus.FORBIDDEN)
public class AccessForbiddenException extends RuntimeException {

public AccessForbiddenException(String message) {
super(message);
log.error(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* 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.exception;

import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@Slf4j
@ResponseStatus(HttpStatus.BAD_REQUEST)
public class InvalidResourceIdException extends RuntimeException {

public InvalidResourceIdException(String message) {
super(message);
log.error(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* 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.interceptors;

import com.opsmx.spinnaker.gate.rbac.ApplicationFeatureRbac;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

@Slf4j
@Component
public class ApplicationIdRbacInterceptor implements HandlerInterceptor {

@Autowired private ApplicationFeatureRbac applicationFeatureRbac;

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
log.info(
"Request intercepted for authorizing if the user is having enough access to perform the action");
applicationFeatureRbac.authorizeUser(
request.getUserPrincipal().getName(), request.getRequestURI(), request.getMethod());
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* 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.interceptors;

import com.opsmx.spinnaker.gate.rbac.ApplicationFeatureRbac;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

@Slf4j
@Component
public class FeatureVisibilityRbacInterceptor implements HandlerInterceptor {

@Autowired private ApplicationFeatureRbac applicationFeatureRbac;

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
log.info("request intercepted to authorize if the user is having feature visibility");
applicationFeatureRbac.authorizeUser(request.getUserPrincipal().getName());
return true;
}
}
Loading

0 comments on commit c87e2a0

Please sign in to comment.