Skip to content

Commit

Permalink
Fix #533: OIDC: Configuration of mobile application
Browse files Browse the repository at this point in the history
  • Loading branch information
banterCZ committed Aug 5, 2024
1 parent b09efa9 commit 11c3776
Show file tree
Hide file tree
Showing 8 changed files with 484 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* PowerAuth integration libraries for RESTful API applications, examples and
* related software components
*
* Copyright (C) 2024 Wultra s.r.o.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.getlime.security.powerauth.rest.api.model.request;

import jakarta.validation.constraints.NotBlank;
import lombok.Data;

/**
* Request object for OIDC application configuration.
*
* @author Lubos Racansky, [email protected]
*/
@Data
public class OidcApplicationConfigurationRequest {

@NotBlank
private String providerId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* PowerAuth integration libraries for RESTful API applications, examples and
* related software components
*
* Copyright (C) 2024 Wultra s.r.o.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.getlime.security.powerauth.rest.api.model.response;

import lombok.Data;

import java.util.List;

/**
* Response object for OIDC application configuration.
*
* @author Lubos Racansky, [email protected]
*/
@Data
//@SuperBuilder
public class OidcApplicationConfigurationResponse {

private String providerId;
private String clientId;
private List<String> scopes;
private String authorizeUri;
private String redirectUri;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* PowerAuth integration libraries for RESTful API applications, examples and
* related software components
*
* Copyright (C) 2024 Wultra s.r.o.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.getlime.security.powerauth.rest.api.spring.exception;

import java.io.Serial;

/**
* Exception for endpoints related to the application configuration endpoint.
*
* @author Lubos Racansky, [email protected]
*/
public class PowerAuthApplicationConfigurationException extends Exception {

@Serial
private static final long serialVersionUID = 8677977961740746599L;

private static final String DEFAULT_CODE = "ERR_APPLICATION_CONFIGURATION";
private static final String DEFAULT_ERROR = "POWER_AUTH_APPLICATION_CONFIGURATION_ERROR";

/**
* Default constructor.
*/
public PowerAuthApplicationConfigurationException() {
super(DEFAULT_ERROR);
}

/**
* Constructor with a custom error message.
* @param message Error message.
*/
public PowerAuthApplicationConfigurationException(String message) {
super(message);
}

/**
* Constructor with a cause.
* @param cause Error cause.
*/
public PowerAuthApplicationConfigurationException(Throwable cause) {
super(cause);
}

/**
* Constructor with a message and cause.
* @param message Error message.
* @param cause Error cause.
*/
public PowerAuthApplicationConfigurationException(String message, Throwable cause) {
super(message, cause);
}


/**
* Get default error code, used for example in the REST response.
* @return Default error code.
*/
public String getDefaultCode() {
return DEFAULT_CODE;
}

/**
* Get default error message, used for example in the REST response.
* @return Default error message.
*/
public String getDefaultError() {
return DEFAULT_ERROR;
}

}
6 changes: 6 additions & 0 deletions powerauth-restful-security-spring/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* PowerAuth integration libraries for RESTful API applications, examples and
* related software components
*
* Copyright (C) 2024 Wultra s.r.o.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.getlime.security.powerauth.rest.api.spring.controller;

import io.getlime.security.powerauth.rest.api.model.request.OidcApplicationConfigurationRequest;
import io.getlime.security.powerauth.rest.api.model.response.OidcApplicationConfigurationResponse;
import io.getlime.security.powerauth.rest.api.spring.annotation.EncryptedRequestBody;
import io.getlime.security.powerauth.rest.api.spring.annotation.PowerAuthEncryption;
import io.getlime.security.powerauth.rest.api.spring.encryption.EncryptionContext;
import io.getlime.security.powerauth.rest.api.spring.encryption.EncryptionScope;
import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthApplicationConfigurationException;
import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthEncryptionException;
import io.getlime.security.powerauth.rest.api.spring.service.ApplicationConfigurationService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
* Controller that provides activation configuration.
*
* @author Lubos Racansky, [email protected]
*/
@RestController
@RequestMapping("/pa/v3/config")
@Slf4j
@AllArgsConstructor
public class OidcActivationConfigurationController {

private ApplicationConfigurationService applicationConfigurationService;

/**
* Fetch OIDC application configuration.
*
* @param request Request OIDC application configuration.
* @param encryptionContext PowerAuth ECIES encryption context.
* @return OIDC application configuration.
* @throws PowerAuthApplicationConfigurationException In case there is an error while fetching claims.
* @throws PowerAuthEncryptionException In case of failed encryption.
*/
@PowerAuthEncryption(scope = EncryptionScope.APPLICATION_SCOPE)
@PostMapping("oidc")
public OidcApplicationConfigurationResponse fetchOidcConfiguration(@EncryptedRequestBody OidcApplicationConfigurationRequest request, EncryptionContext encryptionContext) throws PowerAuthApplicationConfigurationException, PowerAuthEncryptionException {
if (encryptionContext == null) {
logger.error("Encryption failed");
throw new PowerAuthEncryptionException("Encryption failed");
}

return applicationConfigurationService.fetchOidcApplicationConfiguration(ApplicationConfigurationService.OidcQuery.builder()
.providerId(request.getProviderId())
.applicationId(encryptionContext.getApplicationKey())
.build());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,16 @@ public class PowerAuthExceptionHandler {
return new ErrorResponse(ex.getDefaultCode(), ex.getMessage());
}

/**
* Handle {@link PowerAuthApplicationConfigurationException} exceptions.
* @param ex Exception instance.
* @return Error response.
*/
@ExceptionHandler(value = PowerAuthApplicationConfigurationException.class)
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public @ResponseBody ErrorResponse handlePowerAuthUserInfoException(PowerAuthApplicationConfigurationException ex) {
logger.warn(ex.getMessage(), ex);
return new ErrorResponse(ex.getDefaultCode(), ex.getMessage());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* PowerAuth integration libraries for RESTful API applications, examples and
* related software components
*
* Copyright (C) 2024 Wultra s.r.o.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.getlime.security.powerauth.rest.api.spring.service;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wultra.security.powerauth.client.PowerAuthClient;
import com.wultra.security.powerauth.client.model.entity.ApplicationConfigurationItem;
import com.wultra.security.powerauth.client.model.error.PowerAuthClientException;
import com.wultra.security.powerauth.client.model.request.GetApplicationConfigRequest;
import com.wultra.security.powerauth.client.model.response.GetApplicationConfigResponse;
import io.getlime.security.powerauth.rest.api.model.response.OidcApplicationConfigurationResponse;
import io.getlime.security.powerauth.rest.api.spring.exception.PowerAuthApplicationConfigurationException;
import lombok.AllArgsConstructor;
import lombok.Builder;
import org.springframework.stereotype.Service;

import java.util.List;

/**
* Service for application configuration.
*
* @author Lubos Racansky, [email protected]
*/
@Service
@AllArgsConstructor
public class ApplicationConfigurationService {

private static final String OAUTH2_PROVIDERS = "oauth2_providers";

private final PowerAuthClient powerAuthClient;

private final ObjectMapper objectMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

/**
* Fetch OIDC application configuration.
*
* @param query Query object.
* @return OIDC application configuration
* @throws PowerAuthApplicationConfigurationException in case of any error
*/
public OidcApplicationConfigurationResponse fetchOidcApplicationConfiguration(final OidcQuery query) throws PowerAuthApplicationConfigurationException {
final String applicationId = query.applicationId();
final String providerId = query.providerId();

try {
final GetApplicationConfigRequest request = new GetApplicationConfigRequest();
request.setApplicationId(applicationId);
final GetApplicationConfigResponse applicationConfig = powerAuthClient.getApplicationConfig(request);

return applicationConfig.getApplicationConfigs().stream()
.filter(it -> it.getKey().equals(OAUTH2_PROVIDERS))
.findFirst()
.map(ApplicationConfigurationItem::getValues)
.map(it -> convert(it, providerId))
.orElseThrow(() ->
new PowerAuthApplicationConfigurationException("Fetching application configuration failed, application ID: %s, provider ID: %s".formatted(applicationId, providerId)));
} catch (PowerAuthClientException | IllegalArgumentException ex) { // IllegalArgumentException may be thrown by the objectMapper
throw new PowerAuthApplicationConfigurationException("Fetching application configuration failed, application ID: " + applicationId, ex);
}
}

private OidcApplicationConfigurationResponse convert(List<Object> values, String providerId) {
return values.stream()
.map(this::convert)
.filter(it -> it.getProviderId().equals(providerId))
.findFirst()
.orElse(null);
}

private OidcApplicationConfigurationResponse convert(Object value) {
return objectMapper.convertValue(value, OidcApplicationConfigurationResponse.class);
}

@Builder
public record OidcQuery(String providerId, String applicationId) {
}

}
Loading

0 comments on commit 11c3776

Please sign in to comment.