Skip to content
Closed
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
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ spockVersion=2.0-groovy-3.0

gebVersion=4.1
seleniumVersion=3.141.59
jpasetoVersion = 0.7.0

title=Micronaut Security
projectDesc=Official Security Solution for Micronaut
Expand Down
24 changes: 24 additions & 0 deletions security-paseto/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
dependencies {
api "io.micronaut:micronaut-http"
api "io.micronaut:micronaut-http-server"
api project(":security")
api "dev.paseto:jpaseto-api:$jpasetoVersion"

implementation "io.projectreactor:reactor-core"

testImplementation "io.micronaut:micronaut-http-client"
testAnnotationProcessor "io.micronaut:micronaut-inject-java"
testImplementation "io.micronaut:micronaut-http-server-netty"
testImplementation project(":test-suite-utils")
testImplementation project(":test-suite-utils-security")

testRuntimeOnly "dev.paseto:jpaseto-impl:$jpasetoVersion"
testRuntimeOnly "dev.paseto:jpaseto-jackson:$jpasetoVersion"
testRuntimeOnly "dev.paseto:jpaseto-bouncy-castle:$jpasetoVersion"
}
apply from: "${rootProject.projectDir}/gradle/testVerbose.gradle"

test {
testLogging.showStandardStreams = true
testLogging.exceptionFormat = 'full'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2017-2020 original authors
*
* Licensed 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
*
* https://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.
*
*/
package io.micronaut.security.token.paseto.config;

import io.micronaut.core.util.Toggleable;

/**
* Represents configuration of the PASETO token.
*
* @author Utsav Varia
* @since 3.0
*/
public interface PasetoConfiguration extends Toggleable {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright 2017-2020 original authors
*
* Licensed 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
*
* https://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.
*
*/
package io.micronaut.security.token.paseto.config;

import io.micronaut.context.annotation.ConfigurationProperties;
import io.micronaut.context.annotation.Requires;
import io.micronaut.core.util.StringUtils;
import io.micronaut.security.token.config.TokenConfigurationProperties;

/**
* {@link PasetoConfiguration} implementation.
*
* @author Utsav Varia
* @since 3.0
*/
@Requires(property = TokenConfigurationProperties.PREFIX + ".enabled", notEquals = StringUtils.FALSE)
@ConfigurationProperties(PasetoConfigurationProperties.PREFIX)
public class PasetoConfigurationProperties implements PasetoConfiguration {

public static final String PREFIX = TokenConfigurationProperties.PREFIX + ".paseto";
/**
* The default enable value.
*/
public static final boolean DEFAULT_ENABLED = true;

private boolean enabled = DEFAULT_ENABLED;

/**
*
* @return a boolean flag indicating whether PASETO beans should be enabled or not
*/
@Override
public boolean isEnabled() {
return enabled;
}

/**
* Sets whether Paseto security is enabled. Default value ({@value #DEFAULT_ENABLED}).
* @param enabled True if it is
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright 2017-2020 original authors
*
* Licensed 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
*
* https://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.
*/
/**
* PASETO configuration.
*
* @author Utsav Varia
* @since 3.0
*/
package io.micronaut.security.token.paseto.config;
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2017-2020 original authors
*
* Licensed 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
*
* https://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.
*/

package io.micronaut.security.token.paseto.generator;

import dev.paseto.jpaseto.Purpose;
import dev.paseto.jpaseto.Version;

import javax.crypto.SecretKey;

/**
* @author Utsav Varia
* @since 3.0
*/
public interface PasetoTokenConfiguration {

/**
* @return Paseto Version
*/
default Version getVersion() {
return Version.V1;
}

default Purpose getPurpose() {
return Purpose.LOCAL;
}

default SecretKey getSecretKey() {
return null;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* Copyright 2017-2020 original authors
*
* Licensed 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
*
* https://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.
*/
package io.micronaut.security.token.paseto.generator;

import dev.paseto.jpaseto.Purpose;
import dev.paseto.jpaseto.Version;
import dev.paseto.jpaseto.lang.Keys;
import io.micronaut.context.annotation.ConfigurationProperties;
import io.micronaut.security.token.paseto.config.PasetoConfigurationProperties;

import javax.crypto.SecretKey;
import java.util.Base64;

/**
* @author Utsav Varia
* @since 3.0
*/
@ConfigurationProperties(PasetoTokenConfigurationProperties.PREFIX)
public class PasetoTokenConfigurationProperties implements PasetoTokenConfiguration {

public static final String PREFIX = PasetoConfigurationProperties.PREFIX + "token";

/**
* The default token type. Possible values local, public.
*/
public static final Purpose DEFAULT_PURPOSE = Purpose.PUBLIC;

/**
* The default Paseto version. Possible values 1, 2.
*/
public static final Version DEFAULT_VERSION = Version.V1;

/**
* The default secret key.
*/
public static final SecretKey DEFAULT_SECRET_KEY = null;

private Purpose purpose = DEFAULT_PURPOSE;
private Version version = DEFAULT_VERSION;
private SecretKey secretKey = DEFAULT_SECRET_KEY;

/**
* @return An integer indicating version of paseto
*/
@Override
public Version getVersion() {
return version;
}

/**
* Sets Paseto version.
*
* @param version Paseto version
*/
public void setVersion(String version) {
this.version = Version.from(version);
}

/**
* @return return token type
*/
@Override
public Purpose getPurpose() {
return purpose;
}

/**
* Sets Paseto token type.
*
* @param purpose Paseto token type
*/
public void setPurpose(String purpose) {
this.purpose = Purpose.from(purpose);
}

/**
* @return return token type
*/
@Override
public SecretKey getSecretKey() {
return secretKey;
}

/**
* Sets Secret key for Paseto token to encrypt with.
*
* @param secretKey Secret key for encryption
*/
public void setSecretKey(String secretKey) {
byte[] decodedKey = Base64.getDecoder().decode(secretKey);
this.secretKey = Keys.secretKey(decodedKey);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Copyright 2017-2020 original authors
*
* Licensed 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
*
* https://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.
*/
package io.micronaut.security.token.paseto.generator;

import dev.paseto.jpaseto.PasetoBuilder;
import dev.paseto.jpaseto.Pasetos;
import dev.paseto.jpaseto.Purpose;
import dev.paseto.jpaseto.Version;
import io.micronaut.security.authentication.Authentication;
import io.micronaut.security.token.generator.TokenGenerator;
import io.micronaut.security.token.paseto.generator.claims.ClaimsGenerator;
import jakarta.inject.Singleton;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.Optional;

/**
* @author Utsav Varia
* @since 3.0
*/
@Singleton
public class PasetoTokenGenerator implements TokenGenerator {

private static final Logger LOG = LoggerFactory.getLogger(PasetoTokenGenerator.class);

protected final ClaimsGenerator claimsGenerator;
protected final PasetoTokenConfigurationProperties tokenConfigurationProperties;

public PasetoTokenGenerator(ClaimsGenerator claimsGenerator, PasetoTokenConfigurationProperties tokenConfigurationProperties) {
this.claimsGenerator = claimsGenerator;
this.tokenConfigurationProperties = tokenConfigurationProperties;
}

/**
* Returns Paseto Token builder based on configuration.
*
* @return Paseto Builder
*/
public PasetoBuilder<?> getPasetoBuilder() {
if (Version.V1.equals(tokenConfigurationProperties.getVersion())) {
if (Purpose.LOCAL.equals(tokenConfigurationProperties.getPurpose())) {
return Pasetos.V1.LOCAL.builder().setSharedSecret(tokenConfigurationProperties.getSecretKey());
} else {
return Pasetos.V1.PUBLIC.builder();
}
} else {
if (Purpose.LOCAL.equals(tokenConfigurationProperties.getPurpose())) {
return Pasetos.V2.LOCAL.builder().setSharedSecret(tokenConfigurationProperties.getSecretKey());
} else {
return Pasetos.V2.PUBLIC.builder();
}
}
}

/**
* Generate a Paseto from a map of claims.
*
* @param claims the map of claims
* @return the created Paseto
*/
protected String generate(final Map<String, Object> claims) {
// claims builder
final PasetoBuilder<?> builder = getPasetoBuilder();

// add claims
for (final Map.Entry<String, Object> entry : claims.entrySet()) {
builder.claim(entry.getKey(), entry.getValue());
}

return builder.compact();
}

@Override
public Optional<String> generateToken(Authentication authentication, Integer expiration) {
Map<String, Object> claims = claimsGenerator.generateClaims(authentication, expiration);
return generateToken(claims);
}

@Override
public Optional<String> generateToken(Map<String, Object> claims) {
return Optional.of(generate(claims));
}
}
Loading