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

[WIP] Reorganization of authentication and security API. #26

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions bom/opensmarthouse-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.auth</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.auth.jaas</artifactId>
Expand Down
70 changes: 70 additions & 0 deletions bom/opensmarthouse/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@
<artifactId>org.opensmarthouse.core.id</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.io.auth</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.persistence</artifactId>
Expand Down Expand Up @@ -217,11 +222,51 @@
<artifactId>org.opensmarthouse.core.auth</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.auth.apitoken</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.auth.apitoken.provider</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.auth.cookie</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.auth.core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.auth.jaas</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.auth.jwt</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.auth.jwt.provider</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.auth.local</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.auth.local.provider</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.auth.oauth2client</artifactId>
Expand All @@ -232,6 +277,11 @@
<artifactId>org.opensmarthouse.core.auth.oauth2client.core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.auth.password</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.io.net</artifactId>
Expand Down Expand Up @@ -287,11 +337,26 @@
<artifactId>org.opensmarthouse.core.io.http.auth</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.io.http.auth.apitoken</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.io.http.auth.basic</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.io.http.auth.jwt</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.io.http.facade</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.io.monitor</artifactId>
Expand All @@ -307,6 +372,11 @@
<artifactId>org.opensmarthouse.core.io.rest.auth</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.io.rest.auth.local</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.io.rest.binding</artifactId>
Expand Down
18 changes: 18 additions & 0 deletions bundles/org.opensmarthouse.core.auth.apitoken.provider/NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
This content is produced and maintained by the OpenSmartHouse project.

* Project home: https://opensmarthouse.org

Elements of this bundle are copyright to the following -:

* The Eclipse Foundation, having come from the Eclipse SmartHome project
* The openHAB project

== Declared Project Licenses

This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.

== Source Code

https://github.com/opensmarthouse/opensmarthouse-core
40 changes: 40 additions & 0 deletions bundles/org.opensmarthouse.core.auth.apitoken.provider/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?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>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.reactor.bundles</artifactId>
<version>0.9.3-SNAPSHOT</version>
</parent>

<artifactId>org.opensmarthouse.core.auth.apitoken.provider</artifactId>

<name>OpenSmartHouse Core | Bundles | Apitoken Authentication Provider</name>

<dependencies>
<dependency>
<groupId>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.auth.local</artifactId>
</dependency>
<dependency>
<groupId>org.opensmarthouse.core.bundles</groupId>
<artifactId>org.opensmarthouse.core.auth.apitoken</artifactId>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>osgi.cmpn</artifactId>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.core.auth.apitoken.provider.internal;

import org.openhab.core.auth.Authentication;
import org.openhab.core.auth.AuthenticationException;
import org.openhab.core.auth.AuthenticationProvider;
import org.openhab.core.auth.AuthenticationResult;
import org.openhab.core.auth.Credentials;
import org.openhab.core.auth.local.GenericUser;
import org.openhab.core.auth.local.ManagedUser;
import org.openhab.core.auth.local.User;
import org.openhab.core.auth.local.UserApiToken;
import org.openhab.core.auth.local.UserRegistry;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.openhab.core.auth.apitoken.UserApiTokenCredentials;

/**
* Authentication provider which is able to correlate received authentication token.
*
* @author Yannick Schaus - initial contribution
* @author Łukasz Dywicki - Extracted from io.rest.auth module.
*/
@Component
public class ApitokenAuthenticationProvider implements AuthenticationProvider {

private final UserRegistry userRegistry;

@Activate
public ApitokenAuthenticationProvider(@Reference UserRegistry userRegistry) {
this.userRegistry = userRegistry;
}

@Override
public AuthenticationResult authenticate(Credentials credentials) throws AuthenticationException {
if (!(credentials instanceof UserApiTokenCredentials)) {
throw new IllegalArgumentException("Invalid credential type");
}

UserApiTokenCredentials apiTokenCreds = (UserApiTokenCredentials) credentials;
String[] apiTokenParts = apiTokenCreds.getApiToken().split("\\.");
if (apiTokenParts.length != 3 || !UserRegistry.APITOKEN_PREFIX.equals(apiTokenParts[0])) {
throw new AuthenticationException("Invalid API token format");
}
for (User user : userRegistry.getAll()) {
ManagedUser managedUser = (ManagedUser) user;
for (UserApiToken userApiToken : managedUser.getApiTokens()) {
// only check if the name in the token matches
if (!userApiToken.getName().equals(apiTokenParts[1])) {
continue;
}
String[] existingTokenHashAndSalt = userApiToken.getApiToken().split(":");
String incomingTokenHash = UserRegistry.hash(apiTokenCreds.getApiToken(), existingTokenHashAndSalt[1],
UserRegistry.APITOKEN_ITERATIONS).get();

if (incomingTokenHash.equals(existingTokenHashAndSalt[0])) {
return new AuthenticationResult(new GenericUser(managedUser.getName()), credentials.getScheme(),
new Authentication(managedUser.getName(), managedUser.getRoles().stream().toArray(String[]::new), userApiToken.getScope())
);
}
}
}

throw new AuthenticationException("Unknown API token");
}

@Override
public boolean supports(Class<? extends Credentials> type) {
return UserApiTokenCredentials.class.isAssignableFrom(type);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.core.auth.apitoken.provider.internal;

import static org.mockito.Mockito.*;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.openhab.core.auth.AuthenticationException;
import org.openhab.core.auth.local.ManagedUser;
import org.openhab.core.auth.local.UserApiToken;
import org.openhab.core.auth.local.UserRegistry;
import org.openhab.core.auth.apitoken.UserApiTokenCredentials;

@ExtendWith(MockitoExtension.class)
class ApitokenAuthenticationProviderTest {

public static final String TOKEN_X = "X";
public static final String TOKEN_Y = "Y";
public static final String TOKEN_Z = "Z";
private static final String TOKEN_SALT = "asdf";


@Mock
private UserRegistry registry;

private ApitokenAuthenticationProvider provider;

@BeforeEach
public void setup() throws Exception {
provider = new ApitokenAuthenticationProvider(registry);

List<ManagedUser> users = Arrays.asList(
createUser("foo", "x", TOKEN_SALT, TOKEN_X),
createUser("bar", "y", TOKEN_SALT, TOKEN_Y),
createUser("baz", "z", TOKEN_SALT, TOKEN_Z)
);
when(registry.getAll()).thenAnswer((inv) -> users);
}

@Test
public void testApiTokens() throws Exception {
String token1 = UserRegistry.APITOKEN_PREFIX + ".x." + TOKEN_X;
String token2 = UserRegistry.APITOKEN_PREFIX + ".y." + TOKEN_Y;
String token3 = UserRegistry.APITOKEN_PREFIX + ".z." + TOKEN_Z;

provider.authenticate(new UserApiTokenCredentials(token1));
provider.authenticate(new UserApiTokenCredentials(token2));
provider.authenticate(new UserApiTokenCredentials(token3));
}

@Test
public void testInvalidTokens() throws Exception {
String token1 = UserRegistry.APITOKEN_PREFIX + ".x.x";
String token2 = UserRegistry.APITOKEN_PREFIX + ".Y.y";

Assertions.assertThrows(AuthenticationException.class, () -> provider.authenticate(new UserApiTokenCredentials(token1)));
Assertions.assertThrows(AuthenticationException.class, () -> provider.authenticate(new UserApiTokenCredentials(token2)));
}

private ManagedUser createUser(String name, String tokenId, String tokenSalt, String tokenValue) {
ManagedUser user = mock(ManagedUser.class, name);

String token = UserRegistry.APITOKEN_PREFIX + "." + tokenId + "." + tokenValue;
String tokenHash = UserRegistry.hash(token, tokenSalt, UserRegistry.APITOKEN_ITERATIONS).get();
System.out.println(token);

UserApiToken userApiToken = new UserApiToken(tokenId, tokenHash + ":" + tokenSalt, "");
when(user.getApiTokens()).thenReturn(Collections.singletonList(userApiToken));
return user;
}

}
18 changes: 18 additions & 0 deletions bundles/org.opensmarthouse.core.auth.apitoken/NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
This content is produced and maintained by the OpenSmartHouse project.

* Project home: https://opensmarthouse.org

Elements of this bundle are copyright to the following -:

* The Eclipse Foundation, having come from the Eclipse SmartHome project
* The openHAB project

== Declared Project Licenses

This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.

== Source Code

https://github.com/opensmarthouse/opensmarthouse-core
Loading