I am trying to create a keycloak object to register new user with keycloak with the following code:
public Keycloak getInstance() {
if (keycloak == null) {
return KeycloakBuilder.builder()
.realm(realm)
.serverUrl(serverURL)
.clientId(clientID)
.clientSecret(clientSecret)
.grantType(OAuth2Constants.CLIENT_CREDENTIALS)
.build();
}
return keycloak;
}
But i keep getting the following error:
java.lang.ClassCastException: class org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl cannot be cast to class javax.ws.rs.client.ClientBuilder (org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl and javax.ws.rs.client.ClientBuilder are in unnamed module of loader 'app')
at org.keycloak.admin.client.ClientBuilderWrapper.create(ClientBuilderWrapper.java:29) ~[keycloak-admin-client-17.0.1.jar:17.0.1]
at org.keycloak.admin.client.spi.ResteasyClientClassicProvider.newRestEasyClient(ResteasyClientClassicProvider.java:35) ~[keycloak-admin-client-17.0.1.jar:17.0.1]
at org.keycloak.admin.client.Keycloak.newRestEasyClient(Keycloak.java:98) ~[keycloak-admin-client-17.0.1.jar:17.0.1]
at org.keycloak.admin.client.Keycloak.<init>(Keycloak.java:89) ~[keycloak-admin-client-17.0.1.jar:17.0.1]
at org.keycloak.admin.client.KeycloakBuilder.build(KeycloakBuilder.java:146) ~[keycloak-admin-client-17.0.1.jar:17.0.1]
at com.microfinanceBank.Customer.Config.KeycloakProvider.getInstance(KeycloakProvider.java:41) ~[classes/:na]
at com.microfinanceBank.Customer.service.KeycloakAdminClientServices.wow(KeycloakAdminClientServices.java:31) ~[classes/:na]
at com.microfinanceBank.Customer.controller.CustomerController.getCustomer(CustomerController.java:68) ~[classes/:na]
at com.microfinanceBank.Customer.controller.CustomerController$$FastClassBySpringCGLIB$$8c9f9beb.invoke(<generated>) ~[classes/:na]
Below are my keycloak dependencies:
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-admin-client</artifactId>
<version>17.0.1</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version>6.1.0.Alpha1</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jackson2-provider</artifactId>
<version>6.1.0.Alpha1</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-multipart-provider</artifactId>
<version>6.1.0.Alpha1</version>
</dependency>
<dependency>
<groupId>com.guicedee.services</groupId>
<artifactId>jakarta.ws.rs-api</artifactId>
<version>1.2.2.1</version>
</dependency>
What am i doing wrong?
I have tried adding some dependencies yet keep getting error.
Please what should i do.Thanks in advance
You can use keycloak's SDK for your springboot application. Include these two dependencies in the pom.xml
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-starter</artifactId>
<version>18.0.2</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-admin-client</artifactId>
<version>18.0.2</version>
</dependency>
After that create a keycloak's instance in your springboot application.
public Keycloak getAdminKeycloakUser() {
return KeycloakBuilder.builder().serverUrl("keycloak-auth-url")
.grantType("password").realm("realm-name")
.clientId("client-id")
.username("admin-user")
.password("admin-password")
.resteasyClient(new ResteasyClientBuilder().connectionPoolSize(10).build()).build();
}
The above method will get you the admin user which is needed in order to create users into Keycloak.
The next step would be to get the realm as realm manages users.
public RealmResource getRealm() {
return getAdminKeycloakUser().realm(realm);
}
Finally now you can create user by using org.keycloak.representations.idm.UserRepresentation.
public void createUser() {
UserRepresentation userRepresentation = new UserRepresentation();
userRepresentation.setUsername("username");
userRepresentation.setFirstName("first-name");
userRepresentation.setLastName("last-name");
userRepresentation.setEmail("test#email.com");
Response response = getRealm().realmResource.users().create(userRepresentation);
//If user is created successfully 200 is returned for response status.
//Set password flow
CredentialRepresentation passwordCred = new CredentialRepresentation();
String userId = CreatedResponseUtil.getCreatedId(response);
passwordCred.setTemporary(false);
passwordCred.setType("password");
passwordCred.setValue("some-password");
UserResource userResource = realmResource.users().get(userId);
userResource.resetPassword(passwordCred);
}
keycloak-spring-boot-starter is deprecated, don't use it. You might find alternatives here
I wouldn't use keycloak-admin-client neither. Admin API is quite well documented. Just use your favorite REST client (with spring-boot features to configure OAuth2 REST client if you like) and POST a request to your Keycloak server.
UserRepresentation userRepresentation = new UserRepresentation();
userRepresentation.setUsername("username");
userRepresentation.setFirstName("first-name");
userRepresentation.setLastName("last-name");
userRepresentation.setEmail("test#email.com");
// set other required values
javax.ws.rs.core.Response response = KeycloakBuilder.builder().build().realm("your-realm-nam").users().create(userRepresentation);
if (response != null && response.getStatusInfo().getFamily() == Family.SUCCESSFUL)
{
return org.keycloak.admin.client.CreatedResponseUtil.getCreatedId(response); // returns String (Id of created User)
}
Related
wanted to ask a basic question about webflux and resilience4j's retry.
We are running Java SpringBoot with Webflux and Resilience4J (not Spring Cloud Circuit Breaker).
While running the application its giving error (Somehow full stack trace is not coming for me) :
due to exception [reactor.core.publisher.Mono.retryWhen(Ljava/util/function/Function;)Lreactor/core/publisher/Mono;]
Code to build the Retry bean is as follows (we are not using YAML based configuration):
#Bean
public Retry retryConfig(ResilienceCCMConfig resilienceCCMConfig) {
RetryConfig config = RetryConfig.custom().maxAttempts(5)
.waitDuration(Duration.of(1, SECONDS))
.retryExceptions(ServerException.class)
.ignoreExceptions(ClientException.class)
.build();
return RetryRegistry.of(config).retry("retry-config", config);
}
Now we are calling our web client's POST method as below with bean injected from above :
#Autowired
private Retry retryConfig;
return webClient.post().uri(url)
.headers(httpHeaders -> getItemHeaders(httpHeaders, tenantId, bannerId, correlationId))
.body(itemServiceRequestMono, ItemServiceRequest.class)
.retrieve()
.onStatus(HttpStatus::isError, clientResponse -> {
LOGGER.error("Error");
if (clientResponse.statusCode().is5xxClientError()) {
throw new Exception("Something went wrong ");
}
return Mono.empty();
})
.bodyToMono(MyResponse.class)
.transform(RetryOperator.of(retryConfig))
.onErrorResume(ex -> myFallbackMethod(ex));
POM dependency :
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>3.4.3</version>
</dependency>
<dependency>
<groupId>io.github.resilience4j</groupId>
<artifactId>resilience4j-reactor</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId> io.github.resilience4j</groupId>
<artifactId>resilience4j-spring-boot2</artifactId>
<version>1.6.1</version>
</dependency>
Please help .
I'm trying to configure OAuth2 for a Spring project. I used jdbc authentification and my authorization server and resource server are two separate API. My issue is now with the microservices. I'm trying to use this shared authorization server to authenticate the microservices. I can get access_token from the token endpoint.
I can check the access_token from the check_token endpoint.
My resource server configuration:
#SpringBootApplication
#EnableCircuitBreaker
#EnableDiscoveryClient
#EnableResourceServer
public class ProductApiServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ProductApiServiceApplication.class, args);
}
}
And application.yml:
security:
oauth2:
client:
client-id: saba-product-api-service
client-secret: secret123
resource:
id: saba-product-api-service
token-info-uri: http://localhost:9999/uaa/oauth/check_token
And REST controller:
#GetMapping("/user/me")
public Principal user(Principal principal) {
return principal;
}
When I call the /user/me endpoint I get invalid_token.
My Resource Server log:
And my Authorization Server log:
What is wrong with my code?
Update
The problem is because of this code:
I had the same issue. In my case, I was using spring cloud oauth2, Hoxton.SR4 release and it was working. So, I change to Hoxton.SR6 and the issue was throwed. My Authoriation Server also was a Eureka's client, and the issue was origined cause this dependency. There was one dependĂȘncia inside Eureka Client, named jackson-dataformat-xml, and because it the return of check_token endpoint was converted in xml instead json. When RemoteTokenServices called check_token, and the resulta was a xml, it culdn't decerialized in map<String,Object> the right way. If you had more than one aud, scope or authorities, it picked the last one. And the active propertie was trated as string. In my case I solved the issue excluding in Authorization Server the dependency mentioned from Eureka Client, like this:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</exclusion>
</exclusions>
</dependency>
Finally, I replaced
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.4.RELEASE</version>
</dependency>
with
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.5.0.RELEASE</version>
</dependency>
// gh-838
if (map.containsKey("active") && !"true".equals(String.valueOf(map.get("active")))) {
logger.debug("check_token returned active attribute: " + map.get("active"));
throw new InvalidTokenException(accessToken);
}
I create a real time notification functionality using spring quartz library. I create two services as bellow :
1) quartz-service : Which is used to set schedule a for real time notification.
2) task-service : Which is used to create a task and remind through quartz-service.
When task-service call quartz-service through feign client I'm not get any response. But If I call through Rest Template it's working find.
Actually we are used spring boot microservice architecture, In using Rest Template we need to specify URL Hard coded, So we can't achieved Ribbon concept in this case that's why we not interest to use Rest Template.
So please help me if any once face this problem.
quartz-service :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
Rest Controller :
#RestController
#RequestMapping(value = "/quartz/taks", produces = "application/hal+json")
public class QuartzTaskController
{
#Autowired
private QuartzTaskServices quartzTaskServices;
#PostMapping("/reminder")
public ResponseEntity<Object> saveTaskReminder(#RequestBody Task task)
{
quartzTaskServices.saveTaskReminderScheduler(task);
return ResponseEntity.ok().build();
}
}
task-service
Dependency :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
Feign Client :
#RibbonClient(name="quartz-services")
#FeignClient(name="quartz-services")
public interface QuartzProxy
{
#PostMapping("/quartz/taks/reminder")
public ResponseEntity<Object> saveTaskReminder(#RequestBody Task task);
}
Call Feign Client :
#Autowired
private QuartzProxy quartzProxy;
...
.....
......
quartzProxy.saveTaskReminder(task);
I am attempting to connect to an S3 bucket using the access key and secret key credentials.
This works correctly on my local machine. However, when I try to run it on an EC2 instance the execution seems to stop at the line result = s3Client.listObjectsV2(request);. There are no exceptions. There is simply no response. I would really appreciate any help.
Java code
AmazonS3 s3Client = AmazonS3ClientBuilder.standard().withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials(accesskey, secretkey)))
.withRegion(region).build();
ListObjectsV2Result result = null;
List<S3ObjectSummary> objects = null;
String continuationToken = null;
System.out.println("Starting loop to request information");
int count = 1;
do {
ListObjectsV2Request request = new ListObjectsV2Request();
request.setBucketName(bucket);
request.setContinuationToken(continuationToken);
System.out.println("Placing request information #" + count);
result = s3Client.listObjectsV2(request);
System.out.println("Got response for request #" + count++);
continuationToken = result.getNextContinuationToken();
objects = result.getObjectSummaries();
for (S3ObjectSummary os : objects) {
System.out.println(os.getKey());
}
} while (continuationToken != null);
pom.xml
<!-- https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk</artifactId>
<version>1.11.466</version>
</dependency>
S3 Bucket policy
{
"Version": "2012-10-17",
"Id": "Policy1563965234895",
"Statement": [
{
"Sid": "Stmt1563965231235",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::xxxxxxxxxxxx:user/xyz_dev",
]
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::xxxx-yyy-bucket",
"arn:aws:s3:::xxxx-yyy-bucket/*"
]
}
]
}
Thank for your responses. I had multiple issues with the code (it was not an issue with the Amazon S3)
It was the infamous error java.lang.NoSuchFieldError: SIGNING_REGION but only occurring on EC2. It was not caught in the try-catch block surrounding the code but was in the HTTP response.
My project is on Spring Boot it had incorrectly imported different versions of aws-sdk modules
I had another POM entry hadoop-aws that had its own version of aws-sdk
Fix:
Added individual aws-sdk module entries instead of the full aws-java-sdk
com.amazonaws
aws-java-sdk-cognitoidp
<!-- https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-core -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-core</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-cognitoidentity -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-cognitoidentity</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-cognitoidp -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-cognitoidp</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-kms -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-kms</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-s3 -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
</dependency>
Added exclusions to hadoop-aws
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-aws</artifactId>
<version>3.1.1</version>
<exclusions>
<exclusion>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-bundle</artifactId>
</exclusion>
</exclusions>
</dependency>
You mention that your project is a Spring BOOT project.
We are working on a document that will show you how to write a Spring BOOT application that invokes AWS Services (in the document, DynamoDB is used as an example) and deploy it to AWS Elastic Beanstalk.
When you do so, there are a few things you need to do to make a Spring BOOT app work, such as:
Set the port that Spring Boot listens on by adding a new environment variable named SERVER_PORT, with the value 5000.
Add a new variable named AWS_ACCESS_KEY_ID and specify your access
key value.
Add a new variable named AWS_SECRET_ACCESS_KEY and specify your secret key value.
To create an AWS Service client, use a EnvironmentVariableCredentialsProvider - like this to use the environment variables.
Region region = Region.US_EAST_1; DynamoDbClient ddb =
DynamoDbClient.builder()
.region(region)
.credentialsProvider(EnvironmentVariableCredentialsProvider.create())
.build();
When the document is done, I will post it here.
Hope this helps...
Dependencies
org.springframework.cloud:spring-cloud-starter-feign:jar:1.2.2.RELEASE:compile
com.netflix.feign:feign-core:jar:8.16.2:compile
com.netflix.feign:feign-slf4j:jar:8.16.2:compile
com.netflix.feign:feign-jackson:jar:8.15.1:compile
Enabling Feign on SpringBootAppilication
#EnableFeignClients(basePackages = "com.vett.services.bucket.restclient")
Feign interface Client
#FeignClient(name = "myClient", configuration = ClientConfigs.class, url = "https://my-endpoint");
public interface MyClient {
Results in this error
org.springframework.core.annotation.AnnotationConfigurationException: Attribute 'value' in annotation [org.springframework.cloud.netflix.feign.FeignClient] must be declared as an #AliasFor [serviceId], not [name]
So far I have
As its unclear to me what the issue is i have used the value instead of name, my searching has not been successful i have see a few issues with feign annotation but not appear to be similar to this at all
I was getting the same issue, Once I added the below dependency , it started working :
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:Brixton.SR7"}
}
I am using Spring boot 1.4 but Spring 4.3.6. Also Spring feign 1.2.5.RELEASE
This error may occur when using multiple feign clients or bad package architecture. Sometimes this error occurs due to version incompatibilities, but in some projects we may not be able to change the versions. Therefore, you can solve the problem with the following codes. This codes worked for me.
Use this annotation in ApplicationStarter class:
#EnableFeignClients
Feign Client Interface:
import org.springframework.cloud.netflix.feign.FeignClient;
#FeignClient(value = "account-service", url = "${feign.client.account-service}", path = "/account/api/v1")
public interface AccountServiceClient {
#RequestLine("POST /customer/{email}/?name={accountName}")
Long registerCustomer(#Param("email") String email, #Param("accountName") String accountName);
}
Define bean for multiple feign usage:
#Bean
#Qualifier("account-feign-client")
public AccountServiceClient accountServiceClient() {
return Feign.builder().target( AccountServiceClient.class,"${feign.client.account-service}");
}
#Bean
#Qualifier("mail-feign-client")
public MailServiceClient mailServiceClient() {
return Feign.builder().target( MailServiceClient.class,"${feign.client.mail-service}");
}
Autowire in service:
#Autowired
#Qualifier("account-feign-client")
private AccountServiceClient accountServiceClient;
pom.xml:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Brixton.SR7</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
...
</dependencies>