Skip to content
Snippets Groups Projects
Commit 9304aef2 authored by Matej Hrica's avatar Matej Hrica
Browse files

Add token-grabber - a confidential client for getting an access token

parent 1b9371ae
No related branches found
No related tags found
No related merge requests found
Showing
with 324 additions and 0 deletions
......@@ -14,6 +14,7 @@
<module>user-client</module>
<module>report-client</module>
<module>weather-client</module>
<module>token-grabber</module>
</modules>
<packaging>pom</packaging>
<name>airport manager parent</name>
......
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cz.muni.fi.pa165</groupId>
<artifactId>airport-manager</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>token-grabber</artifactId>
<packaging>jar</packaging>
<name>OAuth 2/OIDC Confidential Client for grabbing the token</name>
<build>
<defaultGoal>spring-boot:run</defaultGoal>
<finalName>>token-grabber</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!-- https://docs.spring.io/spring-boot/docs/current/reference/html/deployment.html#deployment.installing -->
<executable>true</executable>
</configuration>
</plugin>
<!-- run integration tests in "mvn verify" phase -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<!-- Spring MVC -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Thymeleaf for HTML pages templates -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- Thymeleaf layout -->
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
</dependency>
<!-- for Spring application.yml properties handling -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- OAuth2/OIDC client -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<!-- web jars for Bootstrap -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator-core</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>5.2.3</version>
</dependency>
</dependencies>
</project>
package cz.muni.pa165.oauth2.client;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
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;
/**
* Spring MVC Controller.
* Handles HTTP requests by preparing data in model and passing it to Thymeleaf HTML templates.
*/
@Controller
public class MainController {
private static final Logger log = LoggerFactory.getLogger(MainController.class);
/**
* Home page accessible even to non-authenticated users. Displays user personal data.
*/
@GetMapping("/")
public String index(Model model, @AuthenticationPrincipal OidcUser user) {
log.debug("index() user {}", user == null ? "is anonymous" : user.getSubject());
// user is logged in
if (user != null) {
return "redirect:/success";
}
return "index";
}
@GetMapping("/success")
public String loggedIn(Model model, @AuthenticationPrincipal OidcUser user,
@RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient oauth2Client) {
OAuth2AccessToken accessToken = oauth2Client.getAccessToken();
log.info("/success :");
var subject = user.getSubject();
model.addAttribute("subject", subject);
log.info("subject: " + subject);
var scopes = accessToken.getScopes();
model.addAttribute("scopes", scopes);
log.info("scopes: " + scopes);
String accessTokenValue = accessToken.getTokenValue();
model.addAttribute("accessToken", accessTokenValue);
log.info("accessToken : " + accessTokenValue);
return "success";
}
}
\ No newline at end of file
package cz.muni.pa165.oauth2.client;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent;
import org.springframework.context.annotation.Bean;
import org.springframework.context.event.EventListener;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler;
@SpringBootApplication
public class WebApp {
private static final Logger log = LoggerFactory.getLogger(WebApp.class);
public static void main(String[] args) {
SpringApplication.run(WebApp.class, args);
}
/**
* Configuration of Spring Security. Sets up OAuth2/OIDC authentication
* for all URLS except a list of public ones.
*/
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.authorizeHttpRequests(x -> x
// allow anonymous access to listed URLs
.requestMatchers("/", "/error", "/robots.txt", "/style.css", "/favicon.ico", "/webjars/**").permitAll()
// all other requests must be authenticated
.anyRequest().authenticated()
)
.oauth2Login(x -> x
.defaultSuccessUrl("/success")
)
.logout(x -> x
.logoutSuccessUrl("/")
)
.csrf(c -> c
//set CSRF token cookie "XSRF-TOKEN" with httpOnly=false that can be read by JavaScript
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
//replace the default XorCsrfTokenRequestAttributeHandler with one that can use value from the cookie
.csrfTokenRequestHandler(new CsrfTokenRequestAttributeHandler())
);
return httpSecurity.build();
}
/**
* Display a hint in the log.
*/
@EventListener
public void onApplicationEvent(final ServletWebServerInitializedEvent event) {
log.info("**************************");
log.info("visit http://localhost:{}/", event.getWebServer().getPort());
log.info("**************************");
}
}
# TCP port for HTTP requests
server:
port: 8081
# OAuth client config
spring:
security:
oauth2:
client:
registration:
muni:
client-id: 7e02a0a9-446a-412d-ad2b-90add47b0fdd
client-secret: 48a2b2e3-4b2b-471e-b7b7-b81a85b6eeef22f347f2-3fc9-4e16-8698-3e2492701a89
client-name: "MUNI Unified Login"
provider: muni
scope:
- openid
- test_1
- test_2
- test_3
provider:
muni:
# URL to which .well-know/openid-configuration will be added to download metadata
issuer-uri: https://oidc.muni.cz/oidc/
# logging config to see interesting things happening
logging:
pattern:
console: '%clr(%d{HH:mm:ss.SSS}){blue} %clr(%-5p) %clr(%logger){blue} %clr(:){red} %m %n'
level:
root: info
cz.muni: debug
org.springframework.web.client.RestTemplate: debug
org.springframework.security: debug
org.springframework.security.web.DefaultSecurityFilterChain: warn
org.springframework.security.web.context.HttpSessionSecurityContextRepository: info
org.springframework.security.web.FilterChainProxy: info
org.springframework.security.web.authentication.AnonymousAuthenticationFilter: info
org.springframework.security.config.annotation.authentication.configuration: info
org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext: warn
org.springframework.boot.web.embedded.tomcat: warn
org.apache.catalina.core: warn
index.title=Airport Manager Login
index.body.annon=You are not logged in. Please log in using your IS MUNI account.
index.body.authuser=You are logged in now.
\ No newline at end of file
token-grabber/src/main/resources/static/favicon.ico

1.12 KiB

User-agent: *
Disallow: /
h1#title a {
text-decoration: none;
color: black;
}
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org/"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout.html}" th:with="title=${#messages.msg('index.title')}">
<body>
<th:block layout:fragment="body">
<p th:text="#{index.body.annon}">text about anonymous user</p>
<p>
<form method="post" th:action="@{/oauth2/authorization/muni}">
<button class="btn btn-outline-primary" type="submit">Login MUNI</button>
</form>
</th:block>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html lang="en" th:lang="${#locale.language}"
xmlns:th="http://www.thymeleaf.org/"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="SHORTCUT ICON" th:href="@{/favicon.ico}">
<link rel="stylesheet" th:href="@{/webjars/bootstrap/css/bootstrap.min.css}"/>
<link rel="stylesheet" type="text/css" th:href="@{/style.css}"/>
<script th:src="@{/webjars/jquery/jquery.min.js}"></script>
<script th:src="@{/webjars/js-cookie/js.cookie.min.js}"></script>
<script th:src="@{/webjars/bootstrap/js/bootstrap.bundle.min.js}"></script>
<title th:text="${title}">Page title</title>
</head>
<body>
<div class="container">
<h1 id="title"><a th:href="@{/}" th:text="${title}">Page title</a></h1>
<th:block layout:fragment="body">
some placeholder text in the page body
</th:block>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org/"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout.html}" th:with="title=${#messages.msg('index.title')}">
<body>
<th:block layout:fragment="body">
<p>You have successfully logged in! Here is your information:
<p>
<table class="table">
<tbody>
<tr>
<th scope="row">subject</th>
<td th:text="${subject}"></td>
</tr>
<tr>
<th scope="row">scopes</th>
<td th:text="${scopes}"></td>
</tr>
<tr>
<th scope="row">accessToken</th>
<td> <textarea readonly th:text="${accessToken}"></textarea></td>
</tr>
</tbody>
</table>
<p>
<form method="post" th:action="@{/logout}">
<button class="btn btn-outline-primary" type="submit">Logout</button>
</form>
</th:block>
</body>
</html>
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment