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

Migrated Hawkbit UI to Vaadin 8 #980

Merged
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7ee8fae
Migrated Hawkbit UI to Vaadin 8
bogdan-bondar Jul 17, 2020
e1f3f2c
fixed some minor sonar issues
bogdan-bondar Jul 20, 2020
61a68ed
fixed license headers
bogdan-bondar Jul 20, 2020
cb444d6
fixed dynamic stylesheet js license header
bogdan-bondar Jul 20, 2020
dff78e4
adapted java docs parameters description, removed unused event classes
bogdan-bondar Jul 20, 2020
49c0767
fixed icon styles, made action icons a little bigger
bogdan-bondar Jul 21, 2020
19bbf7e
fixed download artifact action icon column header, fixed styling for …
bogdan-bondar Jul 22, 2020
c8c3af3
fixed Notification rendering regarding word wrap
bogdan-bondar Jul 24, 2020
c8dde1b
fixed restore behaviour with the invalid target filter query in Filte…
bogdan-bondar Jul 24, 2020
04dbc9c
replaced List collection with Set for better performance during DS pi…
bogdan-bondar Jul 24, 2020
5ec44f2
disable crud menu button on no CUD permissions, disable Rollout Group…
bogdan-bondar Jul 28, 2020
eaddc0d
disable Autoassignment link in case of missing read repository permis…
bogdan-bondar Jul 28, 2020
dd00a56
adapted ordering of columns in maximized state
bogdan-bondar Jul 29, 2020
1d8f899
limited selection in grids to 1000 entities, removed shift+ctrl selec…
bogdan-bondar Aug 4, 2020
6887a3a
added java docs to notification class
bogdan-bondar Aug 4, 2020
6114b76
fixed restoration of the default filter value for grids
bogdan-bondar Aug 10, 2020
b38bd3b
added caption to Delete column in grids, made target filter grid colu…
bogdan-bondar Aug 11, 2020
a1aeac0
removed com.google.gwt.gwtmockito test dependency
bogdan-bondar Aug 17, 2020
8d025ef
renamed RemoteEventsListener to HawkbitEntityEventListener to better …
bogdan-bondar Aug 17, 2020
56a5df4
changed Guava cache to Caffeine cache for EntityModified UI events
bogdan-bondar Aug 17, 2020
151d3d5
removed obsolete HawkbitErrorNotificationMessage, UINotification is u…
bogdan-bondar Aug 17, 2020
535c6f6
added stacked notifications custom extension
bogdan-bondar Aug 18, 2020
41c28bd
removed unused JUnitParams dependency
bogdan-bondar Aug 18, 2020
9150997
fixed license header for ParallelNotificationConnector
bogdan-bondar Aug 18, 2020
947f23f
set ui mode back to production
bogdan-bondar Aug 19, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
9 changes: 9 additions & 0 deletions hawkbit-autoconfigure/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,14 @@
<artifactId>protostuff-runtime</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.vaadin.spring.extensions</groupId>
<artifactId>vaadin-spring-ext-security</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@

import org.eclipse.hawkbit.DistributedResourceBundleMessageSource;
import org.eclipse.hawkbit.ui.MgmtUiConfiguration;
import org.eclipse.hawkbit.ui.SpPermissionChecker;
import org.eclipse.hawkbit.ui.UiProperties;
import org.eclipse.hawkbit.ui.push.DelayedEventBusPushStrategy;
import org.eclipse.hawkbit.ui.push.EventPushStrategy;
import org.eclipse.hawkbit.ui.push.HawkbitEventPermissionChecker;
import org.eclipse.hawkbit.ui.push.HawkbitEventProvider;
import org.eclipse.hawkbit.ui.push.UIEventPermissionChecker;
import org.eclipse.hawkbit.ui.push.UIEventProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
Expand All @@ -26,15 +29,15 @@
import org.vaadin.spring.annotation.EnableVaadinExtensions;
import org.vaadin.spring.events.EventBus.UIEventBus;
import org.vaadin.spring.events.annotation.EnableEventBus;
import org.vaadin.spring.security.annotation.EnableVaadinSecurity;
import org.vaadin.spring.security.annotation.EnableVaadinManagedSecurity;

import com.vaadin.spring.annotation.UIScope;

/**
* The Management UI auto configuration.
*/
@Configuration
@EnableVaadinSecurity
@EnableVaadinManagedSecurity
@EnableVaadinExtensions
@EnableEventBus
@ConditionalOnClass(MgmtUiConfiguration.class)
Expand Down Expand Up @@ -68,6 +71,18 @@ UIEventProvider eventProvider() {
return new HawkbitEventProvider();
}

/**
* A event permission checker bean which verifies supported events for the
* UI.
*
* @return the permission checker bean
*/
@Bean
@ConditionalOnMissingBean
UIEventPermissionChecker eventPermissionChecker(final SpPermissionChecker permChecker) {
return new HawkbitEventPermissionChecker(permChecker);
}

/**
* The UI scoped event push strategy. Session scope is necessary, that every
* UI has an own strategy.
Expand All @@ -80,6 +95,8 @@ UIEventProvider eventProvider() {
* the ui event bus
* @param eventProvider
* the event provider
* @param eventPermissionChecker
* the event permission checker
* @param uiProperties
* the ui properties
* @return the push strategy bean
Expand All @@ -89,10 +106,12 @@ UIEventProvider eventProvider() {
@UIScope
EventPushStrategy eventPushStrategy(final ConfigurableApplicationContext applicationContext,
final ScheduledExecutorService executorService, final UIEventBus eventBus,
final UIEventProvider eventProvider, final UiProperties uiProperties) {
final UIEventProvider eventProvider, final UIEventPermissionChecker eventPermissionChecker,
final UiProperties uiProperties) {
final DelayedEventBusPushStrategy delayedEventBusPushStrategy = new DelayedEventBusPushStrategy(executorService,
eventBus, eventProvider, uiProperties.getEvent().getPush().getDelay());
eventBus, eventProvider, eventPermissionChecker, uiProperties.getEvent().getPush().getDelay());
applicationContext.addApplicationListener(delayedEventBusPushStrategy);

return delayedEventBusPushStrategy;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
package org.eclipse.hawkbit.autoconfigure.mgmt.ui;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;

/**
Expand All @@ -23,7 +23,7 @@ public class RedirectController {
/**
* @return redirect to the Management UI
*/
@RequestMapping("/")
@GetMapping("/")
public ModelAndView home() {
return new ModelAndView("redirect:/UI/");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.vaadin.spring.security.config.AuthenticationManagerConfigurer;

/**
* Auto-configuration for the in-memory-user-management.
Expand All @@ -40,7 +41,8 @@
@Configuration
@ConditionalOnMissingBean(UserDetailsService.class)
@EnableConfigurationProperties({ MultiUserProperties.class })
public class InMemoryUserManagementAutoConfiguration extends GlobalAuthenticationConfigurerAdapter {
public class InMemoryUserManagementAutoConfiguration extends GlobalAuthenticationConfigurerAdapter
implements AuthenticationManagerConfigurer {

private static final String DEFAULT_TENANT = "DEFAULT";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import java.util.Collection;
import java.util.Collections;

import javax.annotation.PostConstruct;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
Expand All @@ -26,7 +25,7 @@
import org.eclipse.hawkbit.ddi.rest.resource.DdiApiConfiguration;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
import org.eclipse.hawkbit.im.authentication.TenantUserPasswordAuthenticationToken;
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
import org.eclipse.hawkbit.im.authentication.UserAuthenticationFilter;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtRestConstants;
import org.eclipse.hawkbit.mgmt.rest.resource.MgmtApiConfiguration;
Expand Down Expand Up @@ -62,7 +61,7 @@
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
Expand Down Expand Up @@ -97,11 +96,12 @@
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.vaadin.spring.security.VaadinSecurityContext;
import org.vaadin.spring.security.annotation.EnableVaadinSecurity;
import org.vaadin.spring.http.HttpService;
import org.vaadin.spring.security.annotation.EnableVaadinSharedSecurity;
import org.vaadin.spring.security.config.VaadinSharedSecurityConfiguration;
import org.vaadin.spring.security.shared.VaadinAuthenticationSuccessHandler;
import org.vaadin.spring.security.shared.VaadinUrlAuthenticationSuccessHandler;
import org.vaadin.spring.security.web.VaadinRedirectStrategy;
import org.vaadin.spring.security.web.authentication.VaadinAuthenticationSuccessHandler;
import org.vaadin.spring.security.web.authentication.VaadinUrlAuthenticationSuccessHandler;

/**
* All configurations related to HawkBit's authentication and authorization
Expand Down Expand Up @@ -530,11 +530,10 @@ protected void configure(final HttpSecurity http) throws Exception {
// Only get the first client registration. Testing against every
// client could increase the
// attack vector
ClientRegistration clientRegistration = null;
for (final ClientRegistration cr : clientRegistrationRepository) {
clientRegistration = cr;
break;
}
final ClientRegistration clientRegistration = clientRegistrationRepository != null
&& clientRegistrationRepository.iterator().hasNext()
? clientRegistrationRepository.iterator().next()
: null;

Assert.notNull(clientRegistration, "There must be a valid client registration");
httpSec.oauth2ResourceServer().jwt().jwkSetUri(clientRegistration.getProviderDetails().getJwkSetUri());
Expand Down Expand Up @@ -596,18 +595,13 @@ CorsConfigurationSource corsConfigurationSource() {
*/
@Configuration
@Order(400)
@EnableVaadinSecurity
@EnableVaadinSharedSecurity
@ConditionalOnClass(MgmtUiConfiguration.class)
public static class UISecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {

@Autowired
private VaadinSecurityContext vaadinSecurityContext;

@Autowired
private HawkbitSecurityProperties hawkbitSecurityProperties;

private final VaadinUrlAuthenticationSuccessHandler handler;

@Autowired(required = false)
private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService;

Expand All @@ -620,14 +614,6 @@ public static class UISecurityConfigurationAdapter extends WebSecurityConfigurer
@Autowired
private LogoutSuccessHandler logoutSuccessHandler;


public UISecurityConfigurationAdapter(final VaadinRedirectStrategy redirectStrategy) {
handler = new TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler();
handler.setRedirectStrategy(redirectStrategy);
handler.setDefaultTargetUrl("/UI/");
handler.setTargetUrlParameter("r");
}

/**
* Filter to protect the hawkBit management UI against to many requests.
*
Expand All @@ -651,26 +637,22 @@ public FilterRegistrationBean<DosFilter> dosMgmtUiFilter(final HawkbitSecurityPr
return filterRegBean;
}

/**
* post construct for setting the authentication success handler for the
* vaadin security context.
*/
@PostConstruct
public void afterPropertiesSet() {
this.vaadinSecurityContext.addAuthenticationSuccessHandler(handler);
}

@Override
@Bean(name = "authenticationManager")
@Bean(name = VaadinSharedSecurityConfiguration.AUTHENTICATION_MANAGER_BEAN)
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}

/**
* @return the vaadin success authentication handler
*/
@Bean
public VaadinAuthenticationSuccessHandler redirectSaveHandler() {
@Bean(name = VaadinSharedSecurityConfiguration.VAADIN_AUTHENTICATION_SUCCESS_HANDLER_BEAN)
public VaadinAuthenticationSuccessHandler redirectSaveHandler(final HttpService httpService,
schabdo marked this conversation as resolved.
Show resolved Hide resolved
final VaadinRedirectStrategy redirectStrategy) {
final VaadinUrlAuthenticationSuccessHandler handler = new TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler(
httpService, redirectStrategy, "/UI/");
handler.setTargetUrlParameter("r");

return handler;
}

Expand Down Expand Up @@ -717,8 +699,8 @@ protected void configure(final HttpSecurity http) throws Exception {
}

// UI
httpSec.authorizeRequests().antMatchers("/UI/login/**", "/UI/UIDL/**").permitAll()
.anyRequest().authenticated();
httpSec.authorizeRequests().antMatchers("/UI/login/**", "/UI/UIDL/**").permitAll().anyRequest()
.authenticated();

if (enableOidc) {
// OIDC
Expand All @@ -737,7 +719,7 @@ protected void configure(final HttpSecurity http) throws Exception {

@Override
public void configure(final WebSecurity webSecurity) throws Exception {
// Not security for static content
// No security for static content
webSecurity.ignoring().antMatchers("/documentation/**", "/VAADIN/**", "/*.*", "/docs/**");
}
}
Expand All @@ -756,30 +738,31 @@ class TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler extends
@Autowired
private SystemSecurityContext systemSecurityContext;

public TenantMetadataSavedRequestAwareVaadinAuthenticationSuccessHandler(final HttpService http,
final VaadinRedirectStrategy redirectStrategy, final String defaultTargetUrl) {
super(http, redirectStrategy, defaultTargetUrl);
}

@Override
public void onAuthenticationSuccess(final Authentication authentication) throws Exception {
systemSecurityContext.runAsSystemAsTenant(systemManagement::getTenantMetadata, getTenantFrom(authentication));

if (authentication.getClass().equals(TenantUserPasswordAuthenticationToken.class)) {
systemSecurityContext.runAsSystemAsTenant(systemManagement::getTenantMetadata,
((TenantUserPasswordAuthenticationToken) authentication).getTenant().toString());
} else if (authentication.getClass().equals(UsernamePasswordAuthenticationToken.class)) {
// TODO: vaadin4spring-ext-security does not give us the
// fullyAuthenticatedToken
// in the GenericVaadinSecurity class. Only the token which has been
// created in the
// LoginView. This needs to be changed with the update of
// vaadin4spring 0.0.7 because it
// has been fixed.
final String defaultTenant = "DEFAULT";
systemSecurityContext.runAsSystemAsTenant(systemManagement::getTenantMetadata, defaultTenant);
super.onAuthenticationSuccess(authentication);
}

private static String getTenantFrom(final Authentication authentication) {
final Object details = authentication.getDetails();
if (details instanceof TenantAwareAuthenticationDetails) {
return ((TenantAwareAuthenticationDetails) details).getTenant();
}

super.onAuthenticationSuccess(authentication);
throw new InsufficientAuthenticationException("Authentication details/tenant info are not specified!");
}
}

/**
* Servletfilter to create metadata after successful authentication over RESTful.
* Servletfilter to create metadata after successful authentication over
* RESTful.
*/
class AuthenticationSuccessTenantMetadataCreationFilter implements Filter {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataCreate;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleMetadataUpdate;
import org.eclipse.hawkbit.repository.builder.SoftwareModuleUpdate;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.EntityAlreadyExistsException;
import org.eclipse.hawkbit.repository.exception.EntityNotFoundException;
import org.eclipse.hawkbit.repository.exception.AssignmentQuotaExceededException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterSyntaxException;
import org.eclipse.hawkbit.repository.exception.RSQLParameterUnsupportedFieldException;
import org.eclipse.hawkbit.repository.model.AssignedSoftwareModule;
Expand Down Expand Up @@ -135,6 +135,21 @@ public interface SoftwareModuleManagement
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
Page<SoftwareModule> findByAssignedTo(@NotNull Pageable pageable, long setId);

/**
* Returns count of all modules assigned to given {@link DistributionSet}.
*
* @param setId
* to search for
*
* @return count of {@link SoftwareModule}s that are assigned to given
* {@link DistributionSet}.
*
* @throws EntityNotFoundException
* if distribution set with given ID does not exist
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_REPOSITORY)
long countByAssignedTo(long setId);

/**
* Filter {@link SoftwareModule}s with given
* {@link SoftwareModule#getName()} or {@link SoftwareModule#getVersion()}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,16 @@ public interface TargetTagManagement {
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
Optional<TargetTag> get(long id);

/**
* Finds {@link TargetTag} by given ids.
*
* @param ids
* the ids to for
* @return the found {@link TargetTag}s
*/
@PreAuthorize(SpringEvalExpressions.HAS_AUTH_READ_TARGET)
List<TargetTag> get(@NotEmpty Collection<Long> ids);

/**
* updates the {@link TargetTag}.
*
Expand Down
Loading