@Transactional(propagation = Propagation.SUPPORTS)
  public boolean hasAccessToDevice(AccessKey accessKey, String deviceGuid) {
    Set<AccessKeyPermission> permissions = accessKey.getPermissions();
    Set<String> allowedDevices = new HashSet<>();
    Set<Long> allowedNetworks = new HashSet<>();

    User accessKeyUser = userService.findUserWithNetworks(accessKey.getUser().getId());
    Set<AccessKeyPermission> toRemove = new HashSet<>();

    Device device =
        genericDAO
            .createNamedQuery(Device.class, "Device.findByUUID", of(CacheConfig.refresh()))
            .setParameter("guid", deviceGuid)
            .getSingleResult();

    for (AccessKeyPermission currentPermission : permissions) {
      if (currentPermission.getDeviceGuidsAsSet() == null) {
        allowedDevices.add(null);
      } else {
        if (!currentPermission.getDeviceGuidsAsSet().contains(deviceGuid)) {
          toRemove.add(currentPermission);
        } else {
          allowedDevices.addAll(currentPermission.getDeviceGuidsAsSet());
        }
      }
      if (currentPermission.getNetworkIdsAsSet() == null) {
        allowedNetworks.add(null);
      } else {
        if (device.getNetwork() != null) {
          if (!currentPermission.getNetworkIdsAsSet().contains(device.getNetwork().getId())) {
            toRemove.add(currentPermission);
          } else {
            allowedNetworks.addAll(currentPermission.getNetworkIdsAsSet());
          }
        }
      }
    }
    permissions.removeAll(toRemove);
    boolean hasAccess;
    hasAccess =
        allowedDevices.contains(null)
            ? userService.hasAccessToDevice(accessKeyUser, device.getGuid())
            : allowedDevices.contains(device.getGuid())
                && userService.hasAccessToDevice(accessKeyUser, device.getGuid());

    hasAccess =
        hasAccess && allowedNetworks.contains(null)
            ? accessKeyUser.isAdmin() || accessKeyUser.getNetworks().contains(device.getNetwork())
            : (accessKeyUser.isAdmin() || accessKeyUser.getNetworks().contains(device.getNetwork()))
                && allowedNetworks.contains(device.getNetwork().getId());

    return hasAccess;
  }
 @Transactional(propagation = Propagation.SUPPORTS)
 public boolean hasAccessToNetwork(AccessKey accessKey, Network targetNetwork) {
   Set<AccessKeyPermission> permissions = accessKey.getPermissions();
   User user = accessKey.getUser();
   boolean hasNullPermission =
       permissions.stream().anyMatch(perm -> perm.getNetworkIdsAsSet() == null);
   if (hasNullPermission) {
     return userService.hasAccessToNetwork(user, targetNetwork);
   } else {
     Set<Long> allowedNetworks =
         permissions
             .stream()
             .map(AccessKeyPermission::getNetworkIdsAsSet)
             .flatMap(Collection::stream)
             .collect(Collectors.toSet());
     user = userService.findUserWithNetworks(user.getId());
     return allowedNetworks.contains(targetNetwork.getId())
         && (user.isAdmin() || user.getNetworks().contains(targetNetwork));
   }
 }
  @Transactional(propagation = Propagation.REQUIRED)
  public AccessKey authenticate(@NotNull User user) {
    userService.refreshUserLoginData(user);

    AccessKey accessKey = authenticationUtils.prepareAccessKey(user);

    Set<AccessKeyPermission> permissions = new HashSet<>();
    final AccessKeyPermission permission = authenticationUtils.preparePermission(user.getRole());
    permissions.add(permission);
    accessKey.setPermissions(permissions);
    genericDAO.persist(accessKey);

    permission.setAccessKey(accessKey);
    genericDAO.persist(permission);
    return accessKey;
  }
  @TransactionAttribute(TransactionAttributeType.SUPPORTS)
  public Network createOrUpdateNetworkByUser(NullableWrapper<Network> network, User user) {
    Network stored;

    // case network is not defined
    if (network == null || network.getValue() == null) {
      return null;
    }

    Network update = network.getValue();

    if (update.getId() != null) {
      stored = networkDAO.getWithDevicesAndDeviceClasses(update.getId());
    } else {
      stored = networkDAO.findByName(update.getName());
    }

    if (stored != null) {
      if (stored.getKey() != null) {
        if (!stored.getKey().equals(update.getKey())) {
          throw new HiveException(Messages.INVALID_NETWORK_KEY, FORBIDDEN.getStatusCode());
        }
      }
      if (!userService.hasAccessToNetwork(user, stored)) {
        throw new HiveException(Messages.NO_ACCESS_TO_NETWORK, FORBIDDEN.getStatusCode());
      }
    } else if (user.isAdmin()) {
      if (update.getId() != null) {
        throw new HiveException(Messages.INVALID_REQUEST_PARAMETERS, BAD_REQUEST.getStatusCode());
      }
      stored = networkDAO.createNetwork(update);

    } else {
      throw new HiveException(Messages.NETWORK_CREATION_NOT_ALLOWED, FORBIDDEN.getStatusCode());
    }
    return stored;
  }
 @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
 public Network getWithDevicesAndDeviceClasses(
     @NotNull Long networkId, @NotNull HivePrincipal principal) {
   if (principal.getUser() != null) {
     List<Network> found =
         networkDAO.getNetworkList(principal.getUser(), null, Arrays.asList(networkId));
     if (found.isEmpty()) {
       return null;
     }
     List<Device> devices = deviceService.getList(networkId, principal);
     Network result = found.get(0);
     result.setDevices(new HashSet<>(devices));
     return result;
   } else {
     AccessKey key = principal.getKey();
     User user = userService.findUserWithNetworks(key.getUser().getId());
     List<Network> found =
         networkDAO.getNetworkList(user, key.getPermissions(), Arrays.asList(networkId));
     Network result = found.isEmpty() ? null : found.get(0);
     if (result == null) {
       return result;
     }
     // to get proper devices 1) get access key with all permissions 2) get devices for required
     // network
     key = accessKeyService.find(key.getId(), principal.getKey().getUser().getId());
     List<AllowedKeyAction.Action> actions = new ArrayList<>();
     actions.add(AllowedKeyAction.Action.GET_DEVICE);
     if (!CheckPermissionsHelper.checkAllPermissions(key, actions)) {
       result.setDevices(null);
       return result;
     }
     Set<Device> devices = new HashSet<>(deviceService.getList(result.getId(), principal));
     result.setDevices(devices);
     return result;
   }
 }