Adding skeleton for JWT authenticator

This commit is contained in:
Martin Stockhammer 2020-07-08 17:34:35 +02:00
parent 54707da343
commit e9eaf8c273
5 changed files with 316 additions and 0 deletions

22
pom.xml
View File

@ -55,6 +55,7 @@
<module>redback-keys</module>
<module>redback-users</module>
<module>redback-integrations</module>
<module>redback-authentication-jwt</module>
</modules>
<scm>
@ -92,6 +93,9 @@
<!-- The git repository, where the site content is placed -->
<siteRepositoryUrl>scm:git:https://gitbox.apache.org/repos/asf/archiva-web-content.git</siteRepositoryUrl>
<jjwt.version>0.11.2</jjwt.version>
</properties>
<repositories>
@ -780,6 +784,24 @@
</exclusions>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>${jjwt.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId> <!-- or jjwt-gson if Gson is preferred -->
<version>${jjwt.version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</dependencyManagement>

View File

@ -35,5 +35,6 @@
<module>redback-authentication-memory</module>
<module>redback-authentication-ldap</module>
<module>redback-authentication-users</module>
<module>redback-authentication-jwt</module>
</modules>
</project>

View File

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Licensed to the Apache Software Foundation (ASF) under one
~ or more contributor license agreements. See the NOTICE file
~ distributed with this work for additional information
~ regarding copyright ownership. The ASF licenses this file
~ to you under the Apache License, Version 2.0 (the
~ "License"); you may not use this file except in compliance
~ with the License. You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
-->
<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.apache.archiva.redback</groupId>
<artifactId>redback-authentication-providers</artifactId>
<version>3.0.0-SNAPSHOT</version>
</parent>
<artifactId>redback-authentication-jwt</artifactId>
<properties>
<site.staging.base>${project.parent.parent.parent.basedir}</site.staging.base>
</properties>
<name>Redback :: Authentication Provider :: JWT</name>
<dependencies>
<dependency>
<groupId>org.apache.archiva.redback</groupId>
<artifactId>redback-authentication-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.archiva.redback</groupId>
<artifactId>redback-policy</artifactId>
</dependency>
<dependency>
<groupId>org.apache.archiva.redback</groupId>
<artifactId>redback-configuration</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
</dependency>
<dependency>
<groupId>jakarta.inject</groupId>
<artifactId>jakarta.inject-api</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,146 @@
package org.apache.archiva.redback.authentication.jwt;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.apache.archiva.redback.authentication.AbstractAuthenticator;
import org.apache.archiva.redback.authentication.AuthenticationDataSource;
import org.apache.archiva.redback.authentication.AuthenticationException;
import org.apache.archiva.redback.authentication.AuthenticationResult;
import org.apache.archiva.redback.authentication.Authenticator;
import org.apache.archiva.redback.authentication.TokenBasedAuthenticationDataSource;
import org.apache.archiva.redback.configuration.UserConfiguration;
import org.apache.archiva.redback.configuration.UserConfigurationKeys;
import org.apache.archiva.redback.policy.AccountLockedException;
import org.apache.archiva.redback.policy.MustChangePasswordException;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.inject.Inject;
import javax.inject.Named;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.util.Base64;
import java.util.Properties;
@Service("authenticator#jwt")
public class JwtAuthenticator extends AbstractAuthenticator implements Authenticator
{
public static final String ID = "JwtAuthenticator";
public static final String PROP_ALG = "algorithm";
public static final String PROP_PRIVATEKEY = "privateKey";
public static final String PROP_PUBLICKEY = "publicKey";
@Inject
@Named( value = "userConfiguration#default" )
UserConfiguration userConfiguration;
boolean symmetricAlg = true;
Key key;
KeyPair keyPair;
String sigAlg;
String keystoreType;
Path keystoreFilePath;
@Override
public String getId( )
{
return ID;
}
@PostConstruct
public void init() {
this.keystoreType = userConfiguration.getString( UserConfigurationKeys.AUTHENTICATION_JWT_KEYSTORETYPE );
this.sigAlg = userConfiguration.getString( UserConfigurationKeys.AUTHENTICATION_JWT_SIGALG );
if ( this.sigAlg.startsWith( "HS" ) ) {
this.symmetricAlg = true;
} else {
this.symmetricAlg = false;
}
if (this.keystoreType.equals(UserConfigurationKeys.AUTHENTICATION_JWT_KEYSTORETYPE_MEMORY))
{
if ( this.symmetricAlg )
{
this.key = createNewSecretKey( this.sigAlg );
} else {
this.keyPair = createNewKeyPair( this.sigAlg );
this.keyPair.getPublic();
}
}
}
private SecretKey createNewSecretKey( String sigAlg) {
return Keys.secretKeyFor( SignatureAlgorithm.forName( sigAlg ));
}
private KeyPair createNewKeyPair(String sigAlg) {
return Keys.keyPairFor( SignatureAlgorithm.forName( sigAlg ));
}
private SecretKey loadKeyFromFile(Path filePath) throws IOException
{
if ( Files.exists( filePath )) {
Properties props = new Properties( );
try ( InputStream in = Files.newInputStream( filePath )) {
props.loadFromXML( in );
}
String algorithm = props.getProperty( PROP_ALG ).trim( );
String secretKey = props.getProperty( PROP_PRIVATEKEY ).trim( );
byte[] keyData = Base64.getDecoder( ).decode( secretKey.getBytes() );
return new SecretKeySpec(keyData, algorithm);
} else {
throw new RuntimeException( "Could not load keyfile from path " );
}
}
private KeyPair loadPairFromFile(Path filePath) throws IOException
{
return null;
}
@Override
public boolean supportsDataSource( AuthenticationDataSource source )
{
return (source instanceof TokenBasedAuthenticationDataSource);
}
@Override
public AuthenticationResult authenticate( AuthenticationDataSource source ) throws AccountLockedException, AuthenticationException, MustChangePasswordException
{
if (source instanceof TokenBasedAuthenticationDataSource ) {
TokenBasedAuthenticationDataSource tSource = (TokenBasedAuthenticationDataSource) source;
return null;
} else {
throw new AuthenticationException( "The provided authentication source is not suitable for this authenticator" );
}
}
}

View File

@ -185,4 +185,68 @@ public interface UserConfigurationKeys
* The locale to use for sending mails and finding mail templates
*/
String MAIL_DEFAULT_LOCALE = "mail.locale";
/**
* Defines, where the key for JWT encryption / decryption is stored.
* Currently only memory and plainfile are supported
*/
String AUTHENTICATION_JWT_KEYSTORETYPE = "authentication.jwt.keystoreType";
String AUTHENTICATION_JWT_KEYSTORETYPE_MEMORY = "memory";
String AUTHENTICATION_JWT_KEYSTORETYPE_PLAINFILE = "plainfile";
String AUTHENTICATION_JWT_SIGALG = "authentication.jwt.signatureAlgorithm";
/**
* HMAC using SHA-256
*/
String AUTHENTICATION_JWT_SIGALG_HS256 = "HS256";
/**
* HMAC using SHA-384
*/
String AUTHENTICATION_JWT_SIGALG_HS384 = "HS384";
/**
* HMAC using SHA-512
*/
String AUTHENTICATION_JWT_SIGALG_HS512 = "HS512";
/**
* ECDSA using P-256 and SHA-256
*/
String AUTHENTICATION_JWT_SIGALG_ES256 = "ES256";
/**
* ECDSA using P-384 and SHA-384
*/
String AUTHENTICATION_JWT_SIGALG_ES384 = "ES384";
/**
* ECDSA using P-521 and SHA-512
*/
String AUTHENTICATION_JWT_SIGALG_ES512 = "ES512";
/**
* RSASSA-PKCS-v1_5 using SHA-256
*/
String AUTHENTICATION_JWT_SIGALG_RS256 = "RS256";
/**
* RSASSA-PKCS-v1_5 using SHA-384
*/
String AUTHENTICATION_JWT_SIGALG_RS384 = "RS384";
/**
* RSASSA-PKCS-v1_5 using SHA-512
*/
String AUTHENTICATION_JWT_SIGALG_RS512 = "RS512";
/**
* RSASSA-PSS using SHA-256 and MGF1 with SHA-256
*/
String AUTHENTICATION_JWT_SIGALG_PS256 = "PS256";
/**
* RSASSA-PSS using SHA-384 and MGF1 with SHA-384
*/
String AUTHENTICATION_JWT_SIGALG_PS384 = "PS384";
/**
* RSASSA-PSS using SHA-512 and MGF1 with SHA-512
*/
String AUTHENTICATION_JWT_SIGALG_PS512 = "PS512";
/**
* Path to the file where the JWT key is stored
*/
String AUTHENTICATION_JWT_KEYFILE = "authentication.jwt.keyfile";
}