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

Feature implement o auth for sec hub web UI #3406 #3473

Merged
merged 22 commits into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
8ed9b3a
add spring security with oauth to web ui
hamidonos Sep 6, 2024
6f9ec88
implement pull request workflow for gha action and gradle action #3357
hamidonos Sep 9, 2024
4c2c51b
add mb sso to application.yml
hamidonos Sep 10, 2024
8ff490b
implement oauth config for sechub webui #3406
hamidonos Sep 11, 2024
3cb3e4a
make web ui spring security oidc config configurable through env vari…
hamidonos Sep 11, 2024
534d3d1
change variable names in application-webui_oidc.yaml
hamidonos Sep 12, 2024
0044d27
Merge branch 'refs/heads/develop' into feature-Implement-OAuth-for-Se…
hamidonos Sep 20, 2024
c6d727f
remove webflux from web ui project
hamidonos Sep 25, 2024
a0fcb54
implement success handler for redirect after successful o auth workfl…
hamidonos Sep 26, 2024
e5bb330
add basic and form login to spring security in web ui
hamidonos Sep 27, 2024
d40d1e0
add under construction site to web ui
hamidonos Sep 30, 2024
84a874b
set default page to /home in webui
hamidonos Sep 30, 2024
8eb1ab1
Merge branch 'refs/heads/develop' into feature-Implement-OAuth-for-Se…
hamidonos Sep 30, 2024
df3b83d
update README.md in web ui
hamidonos Sep 30, 2024
716daff
clean up build.gradle of webui
hamidonos Oct 1, 2024
7e92270
fix formatting in MercedesBenzOAuth2AccessTokenClient
hamidonos Oct 1, 2024
d790b1e
remove unnecessary pages and controller in webui
hamidonos Oct 2, 2024
c52534a
exclude OAuth2Properties with @Profile
hamidonos Oct 2, 2024
ad334a0
exclude OAuth2Properties with @Profile
hamidonos Oct 7, 2024
55ade83
pr fixes
hamidonos Oct 9, 2024
9faf60d
pr fixes
hamidonos Oct 9, 2024
3723668
pr fixes
hamidonos Oct 10, 2024
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
2 changes: 1 addition & 1 deletion gradle/libraries.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ ext {
springboot_starter_mail: "org.springframework.boot:spring-boot-starter-mail",
springboot_starter_validation: "org.springframework.boot:spring-boot-starter-validation",
springboot_starter_webflux: "org.springframework.boot:spring-boot-starter-webflux",

springboot_starter_oauth2_client: "org.springframework.boot:spring-boot-starter-oauth2-client",
springframework_restdocs: "org.springframework.restdocs:spring-restdocs-mockmvc",
springframework_security_test: "org.springframework.security:spring-security-test",
springframework_web: "org.springframework:spring-web",
Expand Down
6 changes: 3 additions & 3 deletions sechub-webui-solution/helm/sechub-webui/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ webui:
appenderName: "LOGSTASH_JSON"
spring:
# Spring profiles (comma-separated list):
# - Server mode: 'webui_localserver' (self-signed cert) or 'webui_server' (provide SSL certificate)
# - SecHub connection: 'webui_mocked' or leave empty for connect to configured SecHub server
profiles: "webui_localserver"
# - Server mode: 'ssl-cert-provided' (self-signed SSL cert included) or 'ssl-cert-required' (SSL certificate required by external config)
# - SecHub connection: 'basic-auth-mocked' or leave empty for connect to configured SecHub server
profiles: "ssl-cert-provided"
hamidonos marked this conversation as resolved.
Show resolved Hide resolved
# Configure Spring Boot's embedded Tomcat
embeddedTomcat:
logging:
Expand Down
2 changes: 2 additions & 0 deletions sechub-webui/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
application-local.*.yaml
application-local.*.yml
61 changes: 61 additions & 0 deletions sechub-webui/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<!-- SPDX-License-Identifier: MIT -->

# SecHub WebUI

## Overview

SecHub WebUI is a web-based user interface for managing and interacting with the SecHub application.

## Profiles

To start the application locally use the `webui_local` profile.

This will include the following profiles:

- `ssl-cert-provided`: a default ssl certificate will be used by the WebUI server
- `basic-auth-mocked`: mock the SecHub Server & enable login with preconfigured credentials at `/login/classic`)
- `local`: includes any local configurations matching `application-local.${USER}.yml`

If you want to provide local configurations, create a file named `application-local.${USER}.yml` in the `src/main/resources` directory.
Make sure that the ${USER} part matches your system username.

This will enable configurations suitable for local development and testing.

## Running the application in OAuth2 Mode

To run the application in OAuth2 mode, include the `oauth2-enabled` profile.

Note: The `webui_prod` profile includes the `oauth2-enabled` profile.

Make sure that you either provide a valid `application-oauth2-enabled.yml` file in the `src/main/resources` directory or set the required environment variables.

Example `application-oauth2-enabled.yml`:

```yaml
sechub:
security:
oauth2:
client-id: example-client-id
client-secret: example-client-secret
provider: example-provider
redirect-uri: {baseUrl}/login/oauth2/code/{provider}
issuer-uri: https://sso.example-provider.com
authorization-uri: https://sso.example-provider.com/as/authorization.oauth2
token-uri: https://sso.example-provider.com/as/token.oauth2
user-info-uri: https://sso.example-provider.com/idp/userinfo.openid
jwk-set-uri: https://sso.example-provider.com/pf/JWKS
```

Alternatively, you can provide the following environment variables:

```bash
SECHUB_SECURITY_OAUTH2_CLIENT_ID=example-client-id
SECHUB_SECURITY_OAUTH2_CLIENT_SECRET=example-client-secret
SECHUB_SECURITY_OAUTH2_PROVIDER=example-provider
SECHUB_SECURITY_OAUTH2_REDIRECT_URI={baseUrl}/login/oauth2/code/{provider}
SECHUB_SECURITY_OAUTH2_ISSUER_URI=https://sso.example-provider.com
SECHUB_SECURITY_OAUTH2_AUTHORIZATION_URI=https://sso.example-provider.com/as/authorization.oauth2
SECHUB_SECURITY_OAUTH2_TOKEN_URI=https://sso.example-provider.com/as/token.oauth2
SECHUB_SECURITY_OAUTH2_USER_INFO_URI=https://sso.example-provider.com/idp/userinfo.openid
SECHUB_SECURITY_OAUTH2_JWK_SET_URI=https://sso.example-provider.com/pf/JWKS
hamidonos marked this conversation as resolved.
Show resolved Hide resolved
```
7 changes: 6 additions & 1 deletion sechub-webui/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,16 @@ plugins {
dependencies {
implementation project(':sechub-commons-core')
implementation project(':sechub-api-java')
implementation library.springboot_starter_web
implementation library.springboot_starter_security
implementation library.springboot_starter_thymeleaf
implementation library.logstashLogbackEncoder
implementation library.springboot_starter_webflux
implementation library.thymeleaf_extras_springsecurity5
implementation library.springboot_starter_oauth2_client
implementation library.findbugs
hamidonos marked this conversation as resolved.
Show resolved Hide resolved

testImplementation library.springboot_starter_test
testImplementation library.springframework_security_test

developmentOnly library.springboot_devtoolssf
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: MIT
package com.mercedesbenz.sechub.webui;

public final class ApplicationProfiles {

public static final String BASIC_AUTH_MOCKED = "basic-auth-mocked";
public static final String INTEGRATION_TEST_DATA = "integrationtest-data";
public static final String LOCAL = "local";
public static final String OAUTH2_ENABLED = "oauth2-enabled";
public static final String SSL_CERT_PROVIDED = "ssl-cert-provided";
public static final String SSL_CERT_REQUIRED = "ssl-cert-required";
public static final String TEST = "test";

private ApplicationProfiles() {
// Prevent instantiation
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
// SPDX-License-Identifier: MIT
package com.mercedesbenz.sechub.webui;

public class RequestConstants {
public final class RequestConstants {

public static final String ROOT = "/";

public static final String PROJECTS = "/projects";
public static final String PROJECT_SCANS = "/projects/{projectId}/scans";
public static final String STATUS = "/status";
public static final String LOGIN = "/login";
public static final String LOGIN_CLASSIC = "/login/classic";
public static final String LOGIN_OAUTH2 = "/login/oauth2";
public static final String HOME = "/home";
public static final String LOGOUT = "/logout";

public static final String REQUEST_NEW_APITOKEN = "/request-new-apitoken";
}
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
// SPDX-License-Identifier: MIT
package com.mercedesbenz.sechub.webui.page.credentials;
package com.mercedesbenz.sechub.webui.credentials;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import com.mercedesbenz.sechub.webui.RequestConstants;
import com.mercedesbenz.sechub.webui.page.user.UserInfoService;
import com.mercedesbenz.sechub.webui.sechubaccess.SecHubAccessService;
import com.mercedesbenz.sechub.webui.user.UserInfoService;

@Controller
public class NewApiTokenController {
class NewApiTokenController {
hamidonos marked this conversation as resolved.
Show resolved Hide resolved

@Autowired
NewApiTokenService newApiTokenService;
private final NewApiTokenService newApiTokenService;
private final SecHubAccessService accessService;
private final UserInfoService userInfoService;

@Autowired
SecHubAccessService accessService;

@Autowired
UserInfoService userInfoService;
NewApiTokenController(NewApiTokenService newApiTokenService, SecHubAccessService accessService, UserInfoService userInfoService) {
hamidonos marked this conversation as resolved.
Show resolved Hide resolved
this.newApiTokenService = newApiTokenService;
this.accessService = accessService;
this.userInfoService = userInfoService;
}

@GetMapping(RequestConstants.REQUEST_NEW_APITOKEN)
String requestNewApiToken(Model model) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
// SPDX-License-Identifier: MIT
package com.mercedesbenz.sechub.webui.page.credentials;
package com.mercedesbenz.sechub.webui.credentials;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.mercedesbenz.sechub.webui.sechubaccess.SecHubAccessService;

@Service
public class NewApiTokenService {
class NewApiTokenService {

@Autowired
SecHubAccessService accessService;
private final SecHubAccessService accessService;

NewApiTokenService(SecHubAccessService accessService) {
this.accessService = accessService;
}

/**
* Request new API token as described in
*
* <a href=
* Request new API token as described in <a href=
* "https://mercedes-benz.github.io/sechub/latest/sechub-restapi.html#user-
* requests-new-api-token">documentation</a>
*
Expand All @@ -25,9 +25,10 @@ public class NewApiTokenService {
* com' -i -X POST -H 'Content-Type: application/json;charset=UTF-8'
* </pre>
*/
public boolean requestNewApiToken(String emailAddress) {
boolean requestNewApiToken(String emailAddress) {
/* @formatter:off */
Boolean succesfulSendNewApiToken = accessService.createExecutorForResult(Boolean.class).

return accessService.createExecutorForResult(Boolean.class).
hamidonos marked this conversation as resolved.
Show resolved Hide resolved
whenDoing("request a new api token").
callAndReturn(client -> {
client.requestNewApiToken(emailAddress);
Expand All @@ -36,8 +37,6 @@ public boolean requestNewApiToken(String emailAddress) {
onErrorReturn(exception -> Boolean.FALSE).
execute();

return succesfulSendNewApiToken;

/* @formatter:on */
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: MIT
package com.mercedesbenz.sechub.webui.page;

import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import com.mercedesbenz.sechub.webui.RequestConstants;

@Controller
public class HomeController {

@GetMapping({ RequestConstants.ROOT, RequestConstants.HOME })
public String home(@AuthenticationPrincipal OidcUser principal, Model model) {
if (principal != null) {
model.addAttribute("principal", principal.getAttribute("name"));
}
return "home";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
import com.mercedesbenz.sechub.webui.RequestConstants;

@Controller
public class LoginController {
public class LoginClassicController {
hamidonos marked this conversation as resolved.
Show resolved Hide resolved

@GetMapping(RequestConstants.LOGIN)
@GetMapping(RequestConstants.LOGIN_CLASSIC)
String login() {
return "login";
return "login-classic";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: MIT
package com.mercedesbenz.sechub.webui.page;

import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import com.mercedesbenz.sechub.webui.ApplicationProfiles;
import com.mercedesbenz.sechub.webui.RequestConstants;

@Controller
@Profile(ApplicationProfiles.OAUTH2_ENABLED)
class LoginOAuth2Controller {

@GetMapping(RequestConstants.LOGIN_OAUTH2)
String login(Model model) {
// TODO: make this configurable later for multiple client registrations
String registrationId = "mercedes-benz";
hamidonos marked this conversation as resolved.
Show resolved Hide resolved
model.addAttribute("registrationId", registrationId);
return "login-oauth2";
}
}

This file was deleted.

This file was deleted.

This file was deleted.

Loading
Loading