Okta SSO from external Partner - java

I made an app which uses Okta for authentication.
A third party partner wants to integrate with me, the steps of integration are:
User signs in on the partner app
User hits a button and is redirected to my app already logged-in
How can I do it? I can create the user server side but I am not able to log in him 😞
here is the Server side code to create the user:
import com.okta.authn.sdk.client.AuthenticationClient;
import com.okta.authn.sdk.client.AuthenticationClients;
import com.okta.sdk.authc.credentials.TokenClientCredentials;
import com.okta.sdk.client.Client;
import com.okta.sdk.client.Clients;
import com.okta.sdk.resource.user.User;
import com.okta.sdk.resource.user.UserBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
#RestController
#RequestMapping("/sso")
public classSSOController {
#GetMapping
public ResponseEntity doStuff(){
Client client = Clients.builder()
.setOrgUrl("XXXXX")
.setClientId("XXXX")
.setClientCredentials(new TokenClientCredentials("XXXXX"))
.build();
Map<String, Object> data = new HashMap<>();
data.put("privacy_consent", true);
data.put("market_consent", true);
data.put("group_id", "XXX");
User user = UserBuilder.instance()
.setEmail("joe.coder"+(int)(Math.random()*1000)+"#example.com")
.setFirstName("JoeTEST")
.setLastName("CodeTEST")
.setProfileProperties(data)
.addGroup("XX")
.setActive(true)
.setPassword("XXXX".toCharArray())
.buildAndCreate(client)
;
return ResponseEntity.ok(user);
}
}
May you help me?

Related

Implementing login endpoint in OpenApi 3.0 Swagger 3

I am using a default endpoint Spring Security using UsernamePasswordAuthenticationFilter. I would like to implement this endpoint in OpenApi 3.0. In the project I already have this implementation in Swagger 2.0 (code below) and now want to change it to OpenApi 3.0. What class can I use instead of ApiListingScanner?
import com.google.common.collect.Multimap;
import lombok.SneakyThrows;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
//import springfox.documentation.builders.ApiListingBuilder;
//import springfox.documentation.builders.OperationBuilder;
//import springfox.documentation.builders.ParameterBuilder;
//import springfox.documentation.schema.ModelRef;
//import springfox.documentation.service.ApiDescription;
//import springfox.documentation.service.ApiListing;
//import springfox.documentation.service.Operation;
//import springfox.documentation.service.ResponseMessage;
//import springfox.documentation.spring.web.plugins.DocumentationPluginsManager;
//import springfox.documentation.spring.web.readers.operation.CachingOperationNameGenerator;
//import springfox.documentation.spring.web.scanners.ApiDescriptionReader;
//import springfox.documentation.spring.web.scanners.ApiListingScanner;
//import springfox.documentation.spring.web.scanners.ApiListingScanningContext;
//import springfox.documentation.spring.web.scanners.ApiModelReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
#Primary
#Configuration
#Profile("!prod")
public class SwaggerLoginConfig extends ApiListingScanner {
public SwaggerLoginConfig(ApiDescriptionReader apiDescriptionReader, ApiModelReader apiModelReader, DocumentationPluginsManager pluginsManager) {
super(apiDescriptionReader, apiModelReader, pluginsManager);
}
#Override
#SneakyThrows
public Multimap<String, ApiListing> scan(ApiListingScanningContext context) {
Multimap<String, ApiListing> def = super.scan(context);
List<ApiDescription> apis = new LinkedList<>();
List<Operation> operations = new ArrayList<>();
operations.add(new OperationBuilder(new CachingOperationNameGenerator())
.method(HttpMethod.POST)
.uniqueId("login")
.parameters(Collections.singletonList(new ParameterBuilder()
.name("body")
.required(true)
.description("The body of request")
.parameterType("body")
.modelRef(new ModelRef("LoginDto"))
.build()))
.responseMessages(Collections.singleton(new ResponseMessage(200, "Correct Response", new ModelRef("LoginResponseDto"), Collections.emptyMap(), Collections.emptyList())))
.consumes(Collections.singleton(MediaType.APPLICATION_JSON.toString()))
.responseModel(new ModelRef("string"))
.summary("Log in")
.notes("Here you can log in")
.build());
apis.add(new ApiDescription("login", "/api/login", "Authentication documentation", operations, false));
def.put("authentication", new ApiListingBuilder(context.getDocumentationContext().getApiDescriptionOrdering())
.apis(apis)
.description("Custom authentication")
.build());
return def;
}
}

Firebase VerifyIdToken in Java Spring backend

I've a mobile application that using Google sign and trying to verify the token in backend (java spring).
I've set a few code for that, following many article.
FirebaseServiceCredential.java
This is for firebase connection, because i'm verifying using Admin SDK
package com.nostratech.nostrafood.config;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;
import com.google.firebase.database.FirebaseDatabase;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import java.io.FileInputStream;
import java.io.IOException;
#Slf4j
#Configuration
public class FirebaseServiceCredential {
public void firebaseConnect() throws IOException {
try {
FileInputStream serviceAccount = new FileInputStream("resources/charity-firebase-adminsdk-ymwjh-61467z75ba.json");
FirebaseOptions options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
.setDatabaseUrl("https://charity.firebaseio.com/")
.build();
FirebaseApp.initializeApp(options);
FirebaseDatabase.getInstance(FirebaseApp.getInstance()).setPersistenceEnabled(true);
} catch (Exception e) {
log.debug("Trying to login to firebase failed. Reason: " + e.getMessage());
}
}
}
GoogleSignInService.java
This is code for verifyIdToken
package com.nostratech.nostrafood.service.base;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseAuthException;
import com.google.firebase.auth.FirebaseToken;
import org.springframework.stereotype.Service;
#Service
public class GoogleSignInService {
public void verifyToken(String idToken) throws FirebaseAuthException {
FirebaseToken decodedToken =
FirebaseAuth.getInstance().verifyIdToken(idToken);
String uid = decodedToken.getUid();
}
}
What should I do next for verify the token? I've read many article but still stuck dont know what to do.
If verifyIdToken() returns without throwing an exception, then the token is verified. No other action is needed to verify an ID token. The return value (FirebaseToken) gives you access to the UID and the JWT claims associated with the authenticated user.

Getting HTTP 401 error while trying to validate the connection.I am using rest assured to automate

/*I have passed session cookies manually in below code.when i pass the session cookies in post man its working fine but in eclipse it giving 401 HTTP error.I am very new to rest assured.please let me know if anything is wrong with the code.I have attached the error aswell */
import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.equalTo;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
import javax.security.cert.CertificateException;
import org.apache.http.HttpResponse;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.testng.annotations.Test;
import com.sun.net.ssl.SSLContext;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import io.restassured.response.ValidatableResponse;
public class getart {
#Test
public void Test1()
{
// TODO Auto-generated method stub
//baseURL or Host
RestAssured.useRelaxedHTTPSValidation();
RestAssured.baseURI="https://localhost";
given().
param("Cookie","JSESSIONID=B1FAC334FF60F7182D4C552ABE01A700; hi.session.co.entity=1838-PROD1; hi.session.id.identifier=xHmvClBuIBcSKAEiVP~~AAAESADWaUjq; hi.session.client.identifier=1838Viewer").
when().
get("/hi-prod/3.1.12/al/api/articles")
.then().assertThat().statusCode(200).
body("status",equalTo("OK")).log().body();
}
}
param() is used to add a query parameter to the URL - which is not something you want for setting the cookies. Cookies have to be set in the Request Header.
Instead you should be using cookie() or cookies(). The rest-assured wiki has a section on how to set the cookies. Note that you will need to set four cookies according to your example.
EDIT: Added as per comment,
Approach 1
Cookie cookie1 = Cookie.Builder("JSESSIONID", "B1FAC334FF60F7182D4C552ABE01A700").build();
Cookie cookie2 = Cookie.Builder("hi.session.co.entity", "1838-PROD1").build();
Cookie cookie3 = Cookie.Builder("hi.session.id.identifier", "xHmvClBuIBcSKAEiVP~~AAAESADWaUjq").build();
Cookie cookie4 = Cookie.Builder("hi.session.client.identifier", "1838Viewer").build();
Cookies cookies = new Cookies(cookie1, cookie2, cookie3, cookie4);
given().cookies(cookies)
.when().get("/hi-prod/3.1.12/al/api/articles")
Approach 2
given().header("Set-Cookie", "JSESSIONID=B1FAC334FF60F7182D4C552ABE01A700; hi.session.co.entity=1838-PROD1; hi.session.id.identifier=xHmvClBuIBcSKAEiVP~~AAAESADWaUjq; hi.session.client.identifier=1838Viewer"")
.when().get("/hi-prod/3.1.12/al/api/articles")

PoolingHttpClientConnectionManager does not release connections

I am using Spring to achieve the following:
On a server, I receive data via a REST interface in an XML-Format. I want to transform the data into JSON and POST it to another Server. My code (I removed some sensitive classnames/URLs to avoid the wrath of my employer) looks like this:
Main/Configuration class:
package stateservice;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
#SpringBootApplication
public class App {
Logger log = LoggerFactory.getLogger(App.class);
public static void main(String[] args) {
System.out.println("Start!");
SpringApplication.run(StateServiceApplication.class, args);
System.out.println("End!");
}
#Bean
public RestTemplate restTemplate() {
log.trace("restTemplate()");
HttpHost proxy = new HttpHost("proxy_url", 8080);
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
// Increase max total connection to 200
cm.setMaxTotal(200);
cm.setDefaultMaxPerRoute(50);
RequestConfig requestConfig = RequestConfig.custom().setProxy(proxy).build();
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
httpClientBuilder.setDefaultRequestConfig(requestConfig);
httpClientBuilder.setConnectionManager(cm);
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(
httpClientBuilder.build());
return new RestTemplate(requestFactory);
}
}
The class representing the RESTful interface:
package stateservice;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import foo.bar.XmlData
#RestController
public class StateController {
private static Logger log = LoggerFactory.getLogger(DataController.class);
#Autowired
ForwarderService forwarder;
#RequestMapping(value = "/data", method = RequestMethod.POST)
public String postState(#RequestBody XmlData data) {
forwarder.forward(data);
return "Done!";
}
}
Finally, the Forwarder:
package stateservice;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import foo.bar.Converter;
import foo.bar.XmlData;
#Service
public class ForwarderService {
private static Logger log = LoggerFactory.getLogger(ForwarderService.class);
String uri = "forward_uri";
#Autowired
RestTemplate restTemplate;
#Async
public String forward(XmlData data) {
log.trace("forward(...) - start");
String json = Converter.convert(data);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
ResponseEntity<String> response = restTemplate.postForEntity(uri,
new HttpEntity<String>(json, headers), String.class);
// responseEntity.getBody();
// log.trace(responseEntity.toString());
log.trace("forward(...) - end");
return response.getBody();
}
}
However, the Connection Manager seldomly seems to release connections for reuse, and additionally, the system gets flooded with connections in the CLOSE_WAIT state (which can be seen using netstat). All connections in the pool get leased, but not released, and as soon as the number of connections in the CLOSE_WAIT state reaches the ulimit, I get 'Too many open files'-exceptions
Because of the multithreaded nature of the code, I suspect that sockets cannot be closed/connections be released, because some other thread is somhow blocking them.
I would really appreciate any help or any hint you can give me to solve the problem.
There is a trick with Apache HttpEntity - to release locked connection - response has to be FULLY consumed and closed. See EntityUtils and HttpEntity docs for details:
EntityUtils.consume(response);
Since version 4.3 Apache HttpClient releases connection back to the pool when #close() method is called on the CloseableHttpResponse.
However this feature is supported by Spring Web only since version 4.0.0-RELEASE, see method #close() in HttpComponentsClientHttpResponse.java:
#Override
public void close() {
// Release underlying connection back to the connection manager
try {
try {
// Attempt to keep connection alive by consuming its remaining content
EntityUtils.consume(this.httpResponse.getEntity());
} finally {
// Paranoia
this.httpResponse.close();
}
}
catch (IOException ignore) {
}
}
The key to success is the line marked by "// Paranoia" - explicit .close() call. It actually releases connection back to pool.

How can I log in with more than one Facebook account?

I am currently trying to get familiar with Spring Social framework. Unfortunately it looks like the code from the tutorial I am following allows only one global login (from the web application point of views).
For example I am connection to Facebook on the laptop I am working on but after opening the app in another browser I am still seeing the details of the user I used in the first place.
Is there a good tutorial which shows how one can authenticate with more than one user at a time?
The "problem" seems to be in the HelloController. Once the user is authorized it is authorized globally for the whole application. How can I change it so it works for multiple logins?
package hello;
import javax.inject.Inject;
import org.springframework.social.facebook.api.Facebook;
import org.springframework.social.facebook.api.PagedList;
import org.springframework.social.facebook.api.Post;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#Controller
#RequestMapping("/")
public class HelloController {
private Facebook facebook;
#Inject
public HelloController(Facebook facebook) {
this.facebook = facebook;
}
#RequestMapping(method=RequestMethod.GET)
public String helloFacebook(Model model) {
if (!facebook.isAuthorized()) {
return "redirect:/connect/facebook";
}
model.addAttribute(facebook.userOperations().getUserProfile());
PagedList<Post> homeFeed = facebook.feedOperations().getHomeFeed();
model.addAttribute("feed", homeFeed);
return "hello";
}
}
EDIT
Making the Facebook instance as request scoped bean does not bring any change. Here is my code.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.core.env.Environment;
import org.springframework.social.UserIdSource;
import org.springframework.social.config.annotation.ConnectionFactoryConfigurer;
import org.springframework.social.config.annotation.EnableSocial;
import org.springframework.social.config.annotation.SocialConfigurerAdapter;
import org.springframework.social.connect.Connection;
import org.springframework.social.connect.ConnectionFactoryLocator;
import org.springframework.social.connect.ConnectionRepository;
import org.springframework.social.connect.web.ConnectController;
import org.springframework.social.facebook.api.Facebook;
import org.springframework.social.facebook.connect.FacebookConnectionFactory;
import my.social.StaticUserIdSource;
#Configuration
#EnableSocial
#PropertySource("classpath:application.properties")
public class SocialConfig extends SocialConfigurerAdapter {
#Configuration
public static class FacebookConfiguration extends SocialConfigurerAdapter {
#Override
public void addConnectionFactories(
ConnectionFactoryConfigurer connectionFactoryConfigurer,
Environment environment) {
connectionFactoryConfigurer
.addConnectionFactory(new FacebookConnectionFactory(
environment.getRequiredProperty("facebook.appId"),
environment
.getRequiredProperty("facebook.appSecret")));
}
#Bean
public ConnectController connectController(ConnectionFactoryLocator connectionFactoryLocator, ConnectionRepository connectionRepository) {
ConnectController connectController = new ConnectController(connectionFactoryLocator, connectionRepository);
return connectController;
}
#Bean
#Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
public Facebook facebookTemplate(ConnectionRepository connectionRepository) {
Connection<Facebook> connection = connectionRepository.findPrimaryConnection(Facebook.class);
return connection != null ? connection.getApi() : null;
}
}
#Override
public UserIdSource getUserIdSource() {
return new StaticUserIdSource();
}
}
In your configuration you are using a StaticUserIdSource judging from the name it uses a predefined user-id. As soon as you have registered a user with the given id (after the first authentication with Facebook that is) that will be used for all other users.

Categories

Resources