Skip to content

Commit 12f57fa

Browse files
author
Travis Tomsu
authored
Merge pull request #24 from ttomsu/google-get-apps
Introduction of fiat-api module.
2 parents 0f59dec + d7b5984 commit 12f57fa

File tree

21 files changed

+630
-156
lines changed

21 files changed

+630
-156
lines changed

README.md

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,11 @@ Roadmap/Implementation Punch list:
1515
* ☐ Compile "to secure" list of endpoints. (In progress)
1616
***Component integration** - wire it all together throughout the other microservices.
1717
* ☑ Gate
18-
* ☐ Front50 (in progress)
19-
* ☐ GET /default/applications
20-
* ☐ PUT /default/applications
21-
* ☐ POST /default/applications/batchUpdate
22-
* ☐ DELETE /default/applications/name/{application}
23-
* ☐ GET /default/applications/name/{application}
24-
* ☐ POST /default/applications/name/{application}
25-
* ☐ GET /default/applications/search
26-
* ☐ GET /default/applications/{application}/history
18+
* ☑ Front50 (in progress)
19+
* Troublesome:
20+
* DELETE /pipelines/deleteById
21+
* DELETE /strategies/deleteById
22+
* NotificationsController
2723
* ☐ Orca
2824
* ☐ Clouddriver
2925
* ☐ Echo

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ allprojects {
3434
apply plugin: 'groovy'
3535

3636
spinnaker {
37-
dependenciesVersion = "0.37.0"
37+
dependenciesVersion = "0.48.0"
3838
}
3939
test {
4040
testLogging {

fiat-api/fiat-api.gradle

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright 2016 Google, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License")
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
dependencies {
18+
compile project(":fiat-core")
19+
20+
spinnaker.group("retrofitDefault")
21+
22+
compile spinnaker.dependency("korkSecurity")
23+
compile spinnaker.dependency("bootActuator")
24+
compile spinnaker.dependency("bootWeb")
25+
26+
compile spinnaker.dependency("springSecurityConfig")
27+
compile spinnaker.dependency("springSecurityCore")
28+
compile spinnaker.dependency("springSecurityWeb")
29+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright 2016 Google, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License")
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.netflix.spinnaker.config;
18+
19+
import com.fasterxml.jackson.databind.ObjectMapper;
20+
import com.netflix.spinnaker.fiat.config.RetrofitConfig;
21+
import com.netflix.spinnaker.fiat.shared.FiatAuthenticationFilter;
22+
import com.netflix.spinnaker.fiat.shared.FiatService;
23+
import lombok.Setter;
24+
import lombok.val;
25+
import org.springframework.beans.factory.annotation.Autowired;
26+
import org.springframework.beans.factory.annotation.Value;
27+
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
28+
import org.springframework.boot.context.embedded.FilterRegistrationBean;
29+
import org.springframework.context.annotation.Bean;
30+
import org.springframework.context.annotation.ComponentScan;
31+
import org.springframework.context.annotation.Configuration;
32+
import org.springframework.context.annotation.Import;
33+
import org.springframework.core.Ordered;
34+
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
35+
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
36+
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
37+
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
38+
import retrofit.Endpoints;
39+
import retrofit.RestAdapter;
40+
import retrofit.client.OkClient;
41+
import retrofit.converter.JacksonConverter;
42+
43+
@EnableWebSecurity
44+
@EnableGlobalMethodSecurity(prePostEnabled = true)
45+
@Configuration
46+
@Import(RetrofitConfig.class)
47+
@ComponentScan("com.netflix.spinnaker.fiat.shared")
48+
public class FiatAuthenticationConfig {
49+
50+
@Autowired
51+
@Setter
52+
private RestAdapter.LogLevel retrofitLogLevel;
53+
54+
@Autowired
55+
@Setter
56+
private ObjectMapper objectMapper;
57+
58+
@Autowired
59+
@Setter
60+
private OkClient okClient;
61+
62+
@Value("${services.fiat.baseUrl}")
63+
@Setter
64+
private String fiatEndpoint;
65+
66+
@Bean
67+
public FiatService fiatService() {
68+
return new RestAdapter.Builder()
69+
.setEndpoint(Endpoints.newFixedEndpoint(fiatEndpoint))
70+
.setClient(okClient)
71+
.setConverter(new JacksonConverter(objectMapper))
72+
.setLogLevel(retrofitLogLevel)
73+
.build()
74+
.create(FiatService.class);
75+
}
76+
77+
@Bean
78+
FilterRegistrationBean fiatFilterRegistrationBean(FiatAuthenticationFilter filter) {
79+
val frb = new FilterRegistrationBean(filter);
80+
frb.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);
81+
frb.addUrlPatterns("/*");
82+
return frb;
83+
}
84+
85+
@ConditionalOnExpression("!${services.fiat.enabled:false}")
86+
@Bean
87+
AnonymousConfig anonymousConfig() {
88+
return new AnonymousConfig();
89+
}
90+
91+
private class AnonymousConfig extends WebSecurityConfigurerAdapter {
92+
@Override
93+
protected void configure(HttpSecurity http) throws Exception {
94+
http.authorizeRequests().anyRequest().permitAll();
95+
}
96+
}
97+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright 2016 Google, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License")
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.netflix.spinnaker.fiat.shared;
18+
19+
import com.netflix.spinnaker.security.AuthenticatedRequest;
20+
import lombok.extern.slf4j.Slf4j;
21+
import lombok.val;
22+
import org.springframework.security.authentication.AnonymousAuthenticationToken;
23+
import org.springframework.security.core.Authentication;
24+
import org.springframework.security.core.authority.AuthorityUtils;
25+
import org.springframework.security.core.context.SecurityContextHolder;
26+
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
27+
import org.springframework.stereotype.Component;
28+
29+
import javax.servlet.*;
30+
import java.io.IOException;
31+
import java.util.ArrayList;
32+
33+
@Slf4j
34+
@Component
35+
public class FiatAuthenticationFilter implements Filter {
36+
37+
@Override
38+
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
39+
Authentication auth = AuthenticatedRequest
40+
.getSpinnakerUser()
41+
.map(username -> (Authentication) new PreAuthenticatedAuthenticationToken(username,
42+
null,
43+
new ArrayList<>()))
44+
.orElseGet(() -> new AnonymousAuthenticationToken(
45+
"ignored1", // These values are never used. See FiatPermissionEvaluator.
46+
"ignored2",
47+
AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS")
48+
));
49+
50+
val ctx = SecurityContextHolder.createEmptyContext();
51+
ctx.setAuthentication(auth);
52+
SecurityContextHolder.setContext(ctx);
53+
chain.doFilter(request, response);
54+
}
55+
56+
@Override
57+
public void init(FilterConfig filterConfig) throws ServletException {
58+
}
59+
60+
@Override
61+
public void destroy() {
62+
}
63+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright 2016 Google, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License")
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.netflix.spinnaker.fiat.shared;
18+
19+
import com.netflix.spinnaker.fiat.model.Authorization;
20+
import com.netflix.spinnaker.fiat.model.resources.Resource;
21+
import lombok.Setter;
22+
import lombok.extern.slf4j.Slf4j;
23+
import org.springframework.beans.factory.annotation.Autowired;
24+
import org.springframework.beans.factory.annotation.Value;
25+
import org.springframework.security.access.PermissionEvaluator;
26+
import org.springframework.security.core.Authentication;
27+
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
28+
import org.springframework.stereotype.Component;
29+
import retrofit.RetrofitError;
30+
31+
import java.io.Serializable;
32+
33+
@Component
34+
@Slf4j
35+
public class FiatPermissionEvaluator implements PermissionEvaluator {
36+
37+
@Autowired
38+
@Setter
39+
private FiatService fiatService;
40+
41+
@Value("${services.fiat.enabled:false}")
42+
@Setter
43+
private String fiatEnabled;
44+
45+
@Override
46+
public boolean hasPermission(Authentication authentication, Object resource, Object authorization) {
47+
return false;
48+
}
49+
50+
@Override
51+
public boolean hasPermission(Authentication authentication, Serializable resourceName, String resourceType, Object authorization) {
52+
if (!Boolean.valueOf(fiatEnabled)) {
53+
return true;
54+
}
55+
56+
String username = getUsername(authentication);
57+
Resource r = Resource.parse(resourceType);
58+
Authorization a = Authorization.valueOf(authorization.toString());
59+
60+
return isAuthorized(username, r, resourceName.toString(), a);
61+
}
62+
63+
private String getUsername(Authentication authentication) {
64+
String username = "anonymous";
65+
if (authentication instanceof PreAuthenticatedAuthenticationToken) {
66+
PreAuthenticatedAuthenticationToken authToken = (PreAuthenticatedAuthenticationToken) authentication;
67+
if (authToken.isAuthenticated()) {
68+
username = authToken.getPrincipal().toString();
69+
}
70+
}
71+
return username;
72+
}
73+
74+
private boolean isAuthorized(String username, Resource resource, String resourceName, Authorization a) {
75+
try {
76+
fiatService.hasAuthorization(username, resource.toString(), resourceName, a.toString());
77+
} catch (RetrofitError re) {
78+
String message = String.format("Fiat authorization failed for user '%s' '%s'-ing '%s' " +
79+
"resource named '%s'. Cause: %s", username, a, resource, resourceName, re.getMessage());
80+
log.debug(message);
81+
log.trace(message, re);
82+
return false;
83+
}
84+
return true;
85+
}
86+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright 2016 Netflix, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License")
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.netflix.spinnaker.fiat.shared;
18+
19+
import com.squareup.okhttp.Response;
20+
import retrofit.http.GET;
21+
import retrofit.http.Path;
22+
23+
public interface FiatService {
24+
25+
@GET("/authorize/{userId}/{resourceType}/{resourceName}/{authorization}")
26+
Response hasAuthorization(@Path("userId") String userId,
27+
@Path("resourceType") String resourceType,
28+
@Path("resourceName") String resourceName,
29+
@Path("authorization") String authorization);
30+
}

fiat-core/fiat-core.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ dependencies {
77
compile spinnaker.dependency("springContext")
88
compile spinnaker.dependency("guava")
99
compile spinnaker.dependency("bootActuator")
10+
compile spinnaker.dependency('korkWeb')
1011

1112
compile "org.apache.commons:commons-lang3:3.4"
1213
compile "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.7.4"

0 commit comments

Comments
 (0)