conversion to jakarta
This commit is contained in:
@ -1,23 +1,17 @@
|
|||||||
package de.jottyfan.timetrack.config;
|
package de.jottyfan.timetrack.config;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.core.convert.converter.Converter;
|
|
||||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
|
||||||
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
import org.springframework.security.oauth2.client.oidc.web.logout.OidcClientInitiatedLogoutSuccessHandler;
|
import org.springframework.security.oauth2.client.oidc.web.logout.OidcClientInitiatedLogoutSuccessHandler;
|
||||||
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
|
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
|
||||||
import org.springframework.security.oauth2.jwt.Jwt;
|
|
||||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
|
||||||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
|
||||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
|
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
|
||||||
|
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
|
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
|
||||||
import de.jottyfan.timetrack.config.converter.KeycloakRealmRoleConverter;
|
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -29,8 +23,10 @@ import de.jottyfan.timetrack.config.converter.KeycloakRealmRoleConverter;
|
|||||||
@EnableMethodSecurity
|
@EnableMethodSecurity
|
||||||
public class SecurityConfiguration {
|
public class SecurityConfiguration {
|
||||||
|
|
||||||
@Value("${spring.security.oauth2.client.provider.keycloak.jwk-set-uri}")
|
@Bean
|
||||||
private String jwtSetUri;
|
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
|
||||||
|
return new NullAuthenticatedSessionStrategy();
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public SecurityFilterChain securityFilterChain(HttpSecurity sec, InMemoryClientRegistrationRepository crr)
|
public SecurityFilterChain securityFilterChain(HttpSecurity sec, InMemoryClientRegistrationRepository crr)
|
||||||
@ -40,19 +36,19 @@ public class SecurityConfiguration {
|
|||||||
.oauth2Login(o -> o.defaultSuccessUrl("/"))
|
.oauth2Login(o -> o.defaultSuccessUrl("/"))
|
||||||
.logout(o -> o.logoutSuccessHandler(new OidcClientInitiatedLogoutSuccessHandler(crr)))
|
.logout(o -> o.logoutSuccessHandler(new OidcClientInitiatedLogoutSuccessHandler(crr)))
|
||||||
.authorizeHttpRequests(o -> o.requestMatchers("/public/**").permitAll().anyRequest().authenticated())
|
.authorizeHttpRequests(o -> o.requestMatchers("/public/**").permitAll().anyRequest().authenticated())
|
||||||
.oauth2ResourceServer(o -> o.jwt(j -> j.jwtAuthenticationConverter(getConverter())));
|
.oauth2ResourceServer(o -> o.jwt(j -> roleConverter()))
|
||||||
|
.sessionManagement(o -> o.init(sec));
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
return sec.build();
|
return sec.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Converter<Jwt, ? extends AbstractAuthenticationToken> getConverter() {
|
|
||||||
JwtAuthenticationConverter jwtConverter = new JwtAuthenticationConverter();
|
|
||||||
jwtConverter.setJwtGrantedAuthoritiesConverter(new KeycloakRealmRoleConverter());
|
|
||||||
return jwtConverter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
JwtDecoder jwtDecoder() {
|
public JwtAuthenticationConverter roleConverter() {
|
||||||
return NimbusJwtDecoder.withJwkSetUri(this.jwtSetUri).build();
|
JwtGrantedAuthoritiesConverter gac = new JwtGrantedAuthoritiesConverter();
|
||||||
|
gac.setAuthorityPrefix("ROLE_");
|
||||||
|
gac.setAuthoritiesClaimName("roles");
|
||||||
|
JwtAuthenticationConverter jac = new JwtAuthenticationConverter();
|
||||||
|
jac.setJwtGrantedAuthoritiesConverter(gac);
|
||||||
|
return jac;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
package de.jottyfan.timetrack.config.converter;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.springframework.core.convert.converter.Converter;
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
|
||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
|
||||||
import org.springframework.security.oauth2.jwt.Jwt;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author henkej
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class KeycloakRealmRoleConverter implements Converter<Jwt, Collection<GrantedAuthority>> {
|
|
||||||
@Override
|
|
||||||
public Collection<GrantedAuthority> convert(Jwt jwt) {
|
|
||||||
Object o = jwt.getClaims().get("realm_access");
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
final Map<String, Object> realmAccess = (Map<String, Object>) o;
|
|
||||||
Object o2 = realmAccess.get("roles");
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
List<String> l = (List<String>) o2;
|
|
||||||
return l.stream().map(roleName -> "ROLE_" + roleName).map(SimpleGrantedAuthority::new).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +1,24 @@
|
|||||||
|
# include properties file from /etc
|
||||||
|
spring.config.import = /etc/timetrack.properties
|
||||||
|
|
||||||
# jooq
|
# jooq
|
||||||
spring.datasource.driver-class-name = org.postgresql.Driver
|
spring.datasource.driver-class-name = org.postgresql.Driver
|
||||||
# todo: export to /etc/timetrack
|
spring.datasource.url = ${db.url}
|
||||||
spring.datasource.url = jdbc:postgresql://localhost:5432/timetrack
|
spring.datasource.username = ${db.username}
|
||||||
spring.datasource.username = timetrack
|
spring.datasource.password = ${db.password}
|
||||||
spring.datasource.password = timetrack
|
|
||||||
|
|
||||||
# security
|
# security
|
||||||
keycloak.url = http://localhost:8080/realms/jottyfan
|
spring.security.oauth2.client.registration.keycloak.client-id = ${keycloak.client-id}
|
||||||
keycloak.openid.url = ${keycloak.url}/protocol/openid-connect
|
|
||||||
spring.security.oauth2.client.registration.keycloak.client-id = timetrack
|
|
||||||
spring.security.oauth2.client.registration.keycloak.scope = openid
|
spring.security.oauth2.client.registration.keycloak.scope = openid
|
||||||
spring.security.oauth2.client.registration.keycloak.authorization-grant-type = authorization_code
|
spring.security.oauth2.client.registration.keycloak.authorization-grant-type = authorization_code
|
||||||
# todo: export to /etc/timetrack
|
spring.security.oauth2.client.registration.keycloak.redirect-uri = ${keycloak.redirect-uri}
|
||||||
spring.security.oauth2.client.registration.keycloak.redirect-uri = http://localhost:8888/timetrack/login/oauth2/code/timetrack
|
spring.security.oauth2.client.provider.keycloak.issuer-uri = ${keycloak.issuer-uri}
|
||||||
spring.security.oauth2.client.provider.keycloak.issuer-uri = ${keycloak.url}
|
spring.security.oauth2.client.provider.keycloak.authorization-uri = ${keycloak.openid-url}/auth
|
||||||
spring.security.oauth2.client.provider.keycloak.authorization-uri = ${keycloak.openid.url}/auth
|
spring.security.oauth2.client.provider.keycloak.token-uri = ${keycloak.openid-url}/token
|
||||||
spring.security.oauth2.client.provider.keycloak.token-uri = ${keycloak.openid.url}/token
|
spring.security.oauth2.client.provider.keycloak.user-info-uri = ${keycloak.openid-url}/userinfo
|
||||||
spring.security.oauth2.client.provider.keycloak.user-info-uri = ${keycloak.openid.url}/userinfo
|
spring.security.oauth2.client.provider.keycloak.jwk-set-uri = ${keycloak.openid-url}/certs
|
||||||
spring.security.oauth2.client.provider.keycloak.jwk-set-uri = ${keycloak.openid.url}/certs
|
|
||||||
spring.security.oauth2.client.provider.keycloak.user-name-attribute = preferred_username
|
spring.security.oauth2.client.provider.keycloak.user-name-attribute = preferred_username
|
||||||
|
|
||||||
# application
|
# application
|
||||||
server:.port = 8083
|
server.port = 8083
|
||||||
server.servlet.context-path = /timetrack
|
server.servlet.context-path = /timetrack
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<font layout:fragment="title">Kalender</font>
|
<font layout:fragment="title">Kalender</font>
|
||||||
<ul layout:fragment="menu">
|
<ul layout:fragment="menu">
|
||||||
<li class="nav-item" sec:authorize="hasRole('timetrack_user')"><a class="btn btn-outline-success" th:href="@{/calendar/add}"><i class="fas fa-plus"></i></a></li>
|
<li class="nav-item" th:if="${#authentication.principal.attributes['resource_access']['timetrack']['roles'].contains('timetrack_user')}"><a class="btn btn-outline-success" th:href="@{/calendar/add}"><i class="fas fa-plus"></i></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<main layout:fragment="content">
|
<main layout:fragment="content">
|
||||||
<ul class="nav nav-tabs navback" role="tablist">
|
<ul class="nav nav-tabs navback" role="tablist">
|
||||||
@ -15,7 +15,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
<div class="tabdivblurred tab-content">
|
<div class="tabdivblurred tab-content">
|
||||||
<div id="div_dashboard" class="tab-pane active tab-pane-glassy">
|
<div id="div_dashboard" class="tab-pane active tab-pane-glassy">
|
||||||
<div sec:authorize="hasRole('timetrack_user')">
|
<div th:if="${#authentication.principal.attributes['resource_access']['timetrack']['roles'].contains('timetrack_user')}">
|
||||||
<div id="calendar"></div>
|
<div id="calendar"></div>
|
||||||
<script th:inline="javascript">
|
<script th:inline="javascript">
|
||||||
/*<![CDATA[*/
|
/*<![CDATA[*/
|
||||||
@ -43,7 +43,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="div_options" class="tab-pane fade tab-pane-table">
|
<div id="div_options" class="tab-pane fade tab-pane-table">
|
||||||
<div sec:authorize="hasRole('timetrack_user')">
|
<div th:if="${#authentication.principal.attributes['resource_access']['timetrack']['roles'].contains('timetrack_user')}">
|
||||||
<!-- TODO: add the options here -->
|
<!-- TODO: add the options here -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
<main layout:fragment="content">
|
<main layout:fragment="content">
|
||||||
<div class="container formpane">
|
<div class="container formpane">
|
||||||
<form th:action="@{/contact/upsert}" th:object="${contactBean}" method="post">
|
<form th:action="@{/contact/upsert}" th:object="${contactBean}" method="post">
|
||||||
<div class="row mb-3">
|
<div class="row mb-3" th:style="${contactBean.pk == null ? 'display: none' : ''}">
|
||||||
<label for="inputPk" class="col-sm-2 col-form-label">Inhalt von Eintrag</label>
|
<label for="inputPk" class="col-sm-2 col-form-label">Inhalt von Eintrag</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<input id="inputPk" type="text" th:field="*{pk}" class="form-control" readonly="readonly" />
|
<input id="inputPk" type="text" th:field="*{pk}" class="form-control" readonly="readonly" />
|
||||||
@ -47,7 +47,7 @@
|
|||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<button type="submit" class="btn btn-success">speichern</button>
|
<button type="submit" class="btn btn-success">speichern</button>
|
||||||
<button type="submit" class="btn btn-secondary" th:formaction="@{/contact/list}">abbrechen</button>
|
<button type="submit" class="btn btn-secondary" th:formaction="@{/contact/list}">abbrechen</button>
|
||||||
<div class="dropdown float-right" th:if="${contactBean.pk != null}" sec:authorize="hasRole('timetrack_user')">
|
<div class="dropdown float-right" th:if="${contactBean.pk != null and #authentication.principal.attributes['resource_access']['timetrack']['roles'].contains('timetrack_user')}">
|
||||||
<button class="btn btn-danger dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">Eintrag löschen</button>
|
<button class="btn btn-danger dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">Eintrag löschen</button>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li><a class="dropdown-item" th:href="@{/contact/delete/{id}(id=${contactBean.pk})}">endgültig löschen</a></li>
|
<li><a class="dropdown-item" th:href="@{/contact/delete/{id}(id=${contactBean.pk})}">endgültig löschen</a></li>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<font layout:fragment="title">Kontakte</font>
|
<font layout:fragment="title">Kontakte</font>
|
||||||
<ul layout:fragment="menu">
|
<ul layout:fragment="menu">
|
||||||
<li class="nav-item" sec:authorize="hasRole('timetrack_user')"><a class="nav-link btn btn-success btn-white-text" th:href="@{/contact/add}">Neuen
|
<li class="nav-item" th:if="${#authentication.principal.attributes['resource_access']['timetrack']['roles'].contains('timetrack_user')}"><a class="nav-link btn btn-success btn-white-text" th:href="@{/contact/add}">Neuen
|
||||||
Kontakt anlegen</a></li>
|
Kontakt anlegen</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<main layout:fragment="content">
|
<main layout:fragment="content">
|
||||||
@ -27,7 +27,7 @@
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="d-flex justify-content-center align-items-center">
|
<div class="d-flex justify-content-center align-items-center">
|
||||||
<span th:text="${contact.type} + ': ' + ${contact.contact}"></span> <a
|
<span th:text="${contact.type} + ': ' + ${contact.contact}"></span> <a
|
||||||
th:href="@{/contact/edit/{id}(id=${contact.pk})}" sec:authorize="hasRole('timetrack_user')" style="margin-left: 8px;">
|
th:href="@{/contact/edit/{id}(id=${contact.pk})}" th:if="${#authentication.principal.attributes['resource_access']['timetrack']['roles'].contains('timetrack_user')}" style="margin-left: 8px;">
|
||||||
<i class="fa fa-edit"></i>
|
<i class="fa fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -93,7 +93,7 @@
|
|||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<button id="okbtn" type="submit" class="btn btn-success">speichern</button>
|
<button id="okbtn" type="submit" class="btn btn-success">speichern</button>
|
||||||
<a class="btn btn-secondary" th:href="@{/done/abort/{day}(day=${doneModel.dayString})}">abbrechen</a>
|
<a class="btn btn-secondary" th:href="@{/done/abort/{day}(day=${doneModel.dayString})}">abbrechen</a>
|
||||||
<div class="dropdown float-right" th:if="${doneBean.pk != null}" sec:authorize="hasRole('timetrack_user')">
|
<div class="dropdown float-right" th:if="${doneBean.pk != null and #authentication.principal.attributes['resource_access']['timetrack']['roles'].contains('timetrack_user')}">
|
||||||
<button class="btn btn-danger dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">Eintrag löschen</button>
|
<button class="btn btn-danger dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">Eintrag löschen</button>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li><a class="dropdown-item" th:href="@{/done/delete/{id}(id=${doneBean.pk})}">endgültig löschen</a></li>
|
<li><a class="dropdown-item" th:href="@{/done/delete/{id}(id=${doneBean.pk})}">endgültig löschen</a></li>
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<button id="okbtn" type="submit" class="btn btn-success">speichern</button>
|
<button id="okbtn" type="submit" class="btn btn-success">speichern</button>
|
||||||
<a class="btn btn-secondary" th:href="@{/done/list}">abbrechen</a>
|
<a class="btn btn-secondary" th:href="@{/done/list}">abbrechen</a>
|
||||||
<div class="dropdown float-right" th:if="${jobBean.pk != null}" sec:authorize="hasRole('timetrack_user')">
|
<div class="dropdown float-right" th:if="${jobBean.pk != null and #authentication.principal.attributes['resource_access']['timetrack']['roles'].contains('timetrack_user')}">
|
||||||
<button class="btn btn-danger dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">Eintrag löschen</button>
|
<button class="btn btn-danger dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">Eintrag löschen</button>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li><a class="dropdown-item" th:href="@{/done/delete/job/{id}(id=${jobBean.pk})}">endgültig löschen</a></li>
|
<li><a class="dropdown-item" th:href="@{/done/delete/job/{id}(id=${jobBean.pk})}">endgültig löschen</a></li>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<font layout:fragment="title">Arbeitszeit</font>
|
<font layout:fragment="title">Arbeitszeit</font>
|
||||||
<ul layout:fragment="menuitem">
|
<ul layout:fragment="menuitem">
|
||||||
<li class="nav-item" sec:authorize="hasRole('timetrack_user')">
|
<li class="nav-item" th:if="${#authentication.principal.attributes['resource_access']['timetrack']['roles'].contains('timetrack_user')}">
|
||||||
<form th:action="@{/done/list}" th:object="${doneModel}" method="post">
|
<form th:action="@{/done/list}" th:object="${doneModel}" method="post">
|
||||||
<div class="nav-link" style="padding-top: 5px !important; padding-bottom: 0px !important">
|
<div class="nav-link" style="padding-top: 5px !important; padding-bottom: 0px !important">
|
||||||
<div class="input-group input-group-sm mb-3" style="margin-bottom: 0px !important">
|
<div class="input-group input-group-sm mb-3" style="margin-bottom: 0px !important">
|
||||||
@ -19,7 +19,7 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul layout:fragment="menu">
|
<ul layout:fragment="menu">
|
||||||
<li class="nav-item" sec:authorize="hasRole('timetrack_user')">
|
<li class="nav-item" th:if="${#authentication.principal.attributes['resource_access']['timetrack']['roles'].contains('timetrack_user')}">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td><a class="nav-link btn btn-success btn-white-text" th:href="@{/done/add/{day}(day=${doneModel.day})}">Neuer
|
<td><a class="nav-link btn btn-success btn-white-text" th:href="@{/done/add/{day}(day=${doneModel.day})}">Neuer
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<button id="okbtn" type="submit" class="btn btn-success">speichern</button>
|
<button id="okbtn" type="submit" class="btn btn-success">speichern</button>
|
||||||
<a class="btn btn-secondary" th:href="@{/done/list}">abbrechen</a>
|
<a class="btn btn-secondary" th:href="@{/done/list}">abbrechen</a>
|
||||||
<div class="dropdown float-right" th:if="${moduleBean.pk != null}" sec:authorize="hasRole('timetrack_user')">
|
<div class="dropdown float-right" th:if="${moduleBean.pk != null and #authentication.principal.attributes['resource_access']['timetrack']['roles'].contains('timetrack_user')}">
|
||||||
<button class="btn btn-danger dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">Eintrag löschen</button>
|
<button class="btn btn-danger dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">Eintrag löschen</button>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li><a class="dropdown-item" th:href="@{/done/delete/module/{id}(id=${moduleBean.pk})}">endgültig löschen</a></li>
|
<li><a class="dropdown-item" th:href="@{/done/delete/module/{id}(id=${moduleBean.pk})}">endgültig löschen</a></li>
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<button id="okbtn" type="submit" class="btn btn-success">speichern</button>
|
<button id="okbtn" type="submit" class="btn btn-success">speichern</button>
|
||||||
<a class="btn btn-secondary" th:href="@{/done/list}">abbrechen</a>
|
<a class="btn btn-secondary" th:href="@{/done/list}">abbrechen</a>
|
||||||
<div class="dropdown float-right" th:if="${projectBean.pk != null}" sec:authorize="hasRole('timetrack_user')">
|
<div class="dropdown float-right" th:if="${projectBean.pk != null and #authentication.principal.attributes['resource_access']['timetrack']['roles'].contains('timetrack_user')}">
|
||||||
<button class="btn btn-danger dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">Eintrag löschen</button>
|
<button class="btn btn-danger dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">Eintrag löschen</button>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li><a class="dropdown-item" th:href="@{/done/delete/project/{id}(id=${projectBean.pk})}">endgültig löschen</a></li>
|
<li><a class="dropdown-item" th:href="@{/done/delete/project/{id}(id=${projectBean.pk})}">endgültig löschen</a></li>
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
<main layout:fragment="content">
|
<main layout:fragment="content">
|
||||||
<div class="container formpane">
|
<div class="container formpane">
|
||||||
<form th:action="@{/note/upsert}" th:object="${noteBean}" method="post">
|
<form th:action="@{/note/upsert}" th:object="${noteBean}" method="post">
|
||||||
<div class="row mb-3">
|
<div class="row mb-3" th:style="${noteBean.pk == null ? 'display: none' : ''}">
|
||||||
<label for="inputPk" class="col-sm-2 col-form-label">Inhalt von Eintrag</label>
|
<label for="inputPk" class="col-sm-2 col-form-label">Inhalt von Eintrag</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<input id="inputPk" type="text" th:field="*{pk}" class="form-control" readonly="readonly" />
|
<input id="inputPk" type="text" th:field="*{pk}" class="form-control" readonly="readonly" />
|
||||||
@ -49,7 +49,7 @@
|
|||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<button type="submit" class="btn btn-success">speichern</button>
|
<button type="submit" class="btn btn-success">speichern</button>
|
||||||
<button type="submit" class="btn btn-secondary" th:formaction="@{/note/list}">abbrechen</button>
|
<button type="submit" class="btn btn-secondary" th:formaction="@{/note/list}">abbrechen</button>
|
||||||
<div class="dropdown float-right" th:if="${noteBean.pk != null}" sec:authorize="hasRole('timetrack_user')">
|
<div class="dropdown float-right" th:if="${noteBean.pk != null and #authentication.principal.attributes['resource_access']['timetrack']['roles'].contains('timetrack_user')}">
|
||||||
<button class="btn btn-danger dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">Eintrag löschen</button>
|
<button class="btn btn-danger dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">Eintrag löschen</button>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li><a class="dropdown-item" th:href="@{/note/delete/{id}(id=${noteBean.pk})}">endgültig löschen</a></li>
|
<li><a class="dropdown-item" th:href="@{/note/delete/{id}(id=${noteBean.pk})}">endgültig löschen</a></li>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<font layout:fragment="title">Notizen</font>
|
<font layout:fragment="title">Notizen</font>
|
||||||
<ul layout:fragment="menu">
|
<ul layout:fragment="menu">
|
||||||
<li class="nav-item" sec:authorize="hasRole('timetrack_user')"><a class="nav-link btn btn-success btn-white-text" th:href="@{/note/add}">Neue Notiz
|
<li class="nav-item" th:if="${#authentication.principal.attributes['resource_access']['timetrack']['roles'].contains('timetrack_user')}"><a class="nav-link btn btn-success btn-white-text" th:href="@{/note/add}">Neue Notiz
|
||||||
anlegen</a></li>
|
anlegen</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<main layout:fragment="content">
|
<main layout:fragment="content">
|
||||||
@ -27,7 +27,7 @@
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="d-flex justify-content-center align-items-center">
|
<div class="d-flex justify-content-center align-items-center">
|
||||||
<pre th:text="${note.content}"></pre>
|
<pre th:text="${note.content}"></pre>
|
||||||
<a th:href="@{/note/edit/{id}(id=${note.pk})}" sec:authorize="hasRole('timetrack_user')" style="margin-left: 8px;">
|
<a th:href="@{/note/edit/{id}(id=${note.pk})}" th:if="${#authentication.principal.attributes['resource_access']['timetrack']['roles'].contains('timetrack_user')}" style="margin-left: 8px;">
|
||||||
<i class="fa fa-edit"></i>
|
<i class="fa fa-edit"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -41,6 +41,18 @@
|
|||||||
th:text="${sum.getBillingTime(null)}" class="distfat"></span>
|
th:text="${sum.getBillingTime(null)}" class="distfat"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- for debugging only, set display to block -->
|
||||||
|
<div class="card" style="display: none">
|
||||||
|
<div class="card-body">
|
||||||
|
<span th:text="${#authentication.principal.attributes['resource_access']['timetrack']['roles']}"></span><br />
|
||||||
|
<span th:if="${#authentication.principal.attributes['resource_access']['timetrack']['roles'].contains('timetrack_user')}">role timetrack_user found directly</span><br />
|
||||||
|
<span sec:authorize="hasRole('timetrack_user')" style="color: green">well done</span>
|
||||||
|
<span sec:authorize="!hasRole('timetrack_user')" style="color: rgb(165, 29, 45)">role timetrack_user not yet detected</span>
|
||||||
|
<br />
|
||||||
|
<span>found roles:</span><br />
|
||||||
|
<span th:each="r : ${#authentication.principal.attributes['resource_access']['timetrack']['roles']}" th:if="${r}" th:text="${r + ' '}" style="color: royalblue"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user