I am using jersey filter.
In My code logic in AuthenticationFilter.java, if the authorization header is empty, then return the access denied error message.
First time I am hitting the application through rest client tool using the URL without attaching the header
http://localhost:8080/JerseyDemos2/rest/pocservice
Get the status 401 with error message "you cannot access this resource". This is right.
When i tried to hit second time thorugh rest client tool, and server return the exception message.
I deployed my application in tomcat 7.x both windows and linux
Why it give the error when we hit the second time.
How to resolve this
#Provider
public class AuthenticationFilter implements javax.ws.rs.container.ContainerRequestFilter {
#Context
private ResourceInfo resourceInfo;
private static final String AUTHORIZATION_PROPERTY = "Authorization";
private static final Response ACCESS_DENIED = Response.status(Response.Status.UNAUTHORIZED).entity("You cannot access this resource").build();
#Override
public void filter(ContainerRequestContext requestContext) {
// Get request headers
final MultivaluedMap<String, String> headers = requestContext.getHeaders();
// Fetch authorization header
final List<String> authorization = headers.get(AUTHORIZATION_PROPERTY);
// If no authorization information present; block access
if (authorization == null || authorization.isEmpty()) {
requestContext.abortWith(ACCESS_DENIED);
return;
}
}
} }
Error message:
Dec 19, 2016 6:26:18 PM org.glassfish.jersey.server.ServerRuntime$Responder writeResponse
SEVERE: An I/O error has occurred while writing a response message entity to the container output stream.
java.lang.IllegalStateException: The output stream has already been closed.
at org.glassfish.jersey.message.internal.CommittingOutputStream.setStreamProvider(CommittingOutputStream.java:147)
at org.glassfish.jersey.message.internal.OutboundMessageContext.setStreamProvider(OutboundMessageContext.java:803)
......
Please help me
Thanks in advance.
I Removed static variable
private static final Response ACCESS_DENIED = Response.status(Response.Status.UNAUTHORIZED).entity("You cannot access this resource").build();
and i declared local variable. now its working fine.
#Provider
public class AuthenticationFilter implements javax.ws.rs.container.ContainerRequestFilter {
#Context
private ResourceInfo resourceInfo;
private static final String AUTHORIZATION_PROPERTY = "Authorization";
#Override
public void filter(ContainerRequestContext requestContext) {
Response ACCESS_DENIED = Response.status(Response.Status.UNAUTHORIZED).entity("You cannot access this resource").build();
// Get request headers
final MultivaluedMap<String, String> headers = requestContext.getHeaders();
// Fetch authorization header
final List<String> authorization = headers.get(AUTHORIZATION_PROPERTY);
// If no authorization information present; block access
if (authorization == null || authorization.isEmpty()) {
requestContext.abortWith(ACCESS_DENIED);
return;
}
}
} }
You're trying to write in a response that was written before. The full log shows where is it happening. Upload the log and the code where the httpresponse is used/modified.
Related
I'm allowing users logged in an external application to jump into our application with their access token through Keycloak's identity brokering and external to internal token exchange.
Now I'd like to establish an SSO session in an embedded JxBrowser in our application similar to a regular browser login flow, where three cookies are set in the browser: AUTH_SESSION, KEYCLOAK_SESSION(_LEGACY) and KEYCLOAK_IDENTITY(_LEGACY).
KEYCLOAK_IDENTITY contains a token of type Serialized-ID which looks somewhat similar to an ID token.
Is it possible to create the KEYCLOAK_IDENTITY cookie using the exchanged (internal) access and/or ID token and, provided that the other two cookies are correctly created as well, would this establish a valid SSO session?
Basically all I am missing is how I could obtain or create the Serialized-ID type token.
One way to achieve this:
Implement a custom endpoint following this example
Note that the provider works fine for me without registering it in standalone.xml, I'm just adding the JAR to the Keycloak Docker image.
Add a method that validates a given access token, looks up the user, gets the user session and sets the cookies in the response (most error handling omitted for brevity):
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("sso")
public Response sso(#Context final HttpRequest request) {
final HttpHeaders headers = request.getHttpHeaders();
final String authorization = headers.getHeaderString(HttpHeaders.AUTHORIZATION);
final String[] value = authorization.split(" ");
final String accessToken = value[1];
final AccessToken token = Tokens.getAccessToken(accessToken, keycloakSession);
if (token == null) {
throw new ErrorResponseException(Errors.INVALID_TOKEN, "Invalid access token", Status.UNAUTHORIZED);
}
final RealmModel realm = keycloakSession.getContext().getRealm();
final UriInfo uriInfo = keycloakSession.getContext().getUri();
final ClientConnection clientConnection = keycloakSession.getContext().getConnection();
final UserModel user = keycloakSession.users().getUserById(token.getSubject(), realm);
final UserSessionModel userSession = keycloakSession.sessions().getUserSession(realm, token.getSessionState());
AuthenticationManager.createLoginCookie(keycloakSession, realm, user, userSession, uriInfo, clientConnection);
return Response.noContent().build();
}
Disclaimer: I am not completely certain this implementation does not imply any security issues, but since Tokens.getAccessToken(accessToken, keycloakSession) does full validation of the access token, setting the cookies should only be possible with a valid access token.
For CORS, add:
#OPTIONS
#Produces(MediaType.APPLICATION_JSON)
#Path("sso")
public Response preflight(#Context final HttpRequest request) {
return Cors.add(request, Response.ok("", MediaType.APPLICATION_JSON))
.auth()
.preflight()
.allowedMethods("GET", "OPTIONS")
.build();
}
and in sso():
return Cors.add(request, Response.ok("", MediaType.APPLICATION_JSON))
.auth()
.allowedMethods("GET")
.allowedOrigins(token)
.build();
What I am uncertain about is why Firefox preflights the GET request, making it necessary to handle that.
Im totally new to AWS. Im trying to use the AWS S3 notification API's. Im receiving the following error.
com.amazonaws.services.sns.model.AmazonSNSException: The security token included in the request is invalid. (Service: AmazonSNS; Status Code: 403; Error Code: InvalidClientTokenId; ...
I have NO idea what's wrong. For my accessID and secretID. Im using the main AWS codes for authentication. Am I supposed to use the main AWS credentials, or something else. Im not using any type of certificate. I dont know if they are even required.
Im using the example code supplied by AWS with some modifications to read a property file instead of hard coding the accessID and secretID.
Can someone please steer me in the right direction? I am completely confused.
public class AmazonSNSReceiver {
// AWS credentials -- replace with your credentials
static String ACCESS_KEY;
static String SECRET_KEY;
// Shared queue for notifications from HTTP server
static BlockingQueue<Map<String, String>> messageQueue = new LinkedBlockingQueue<Map<String, String>>();
// Receiver loop
public static void main(String[] args) throws Exception {
AmazonSNSReceiver sns = new AmazonSNSReceiver();
sns.getPropertyValues();
if (args.length == 1) {
sns.SNSClient(args[0]);
} else {
sns.SNSClient("8989");
}
}
// Create a client
public void SNSClient(String thisport) throws Exception{
AmazonSNSClient service = new AmazonSNSClient(new BasicAWSCredentials(ACCESS_KEY, SECRET_KEY));
// Create a topic
CreateTopicRequest createReq = new CreateTopicRequest().withName("MyTopic");
CreateTopicResult createRes = service.createTopic(createReq);
// Get an HTTP Port
int port = thisport == null ? 8989 : Integer.parseInt(thisport);
// Create and start HTTP server
Server server = new Server(port);
server.setHandler(new AmazonSNSHandler());
server.start();
// Subscribe to topic
SubscribeRequest subscribeReq = new SubscribeRequest()
.withTopicArn(createRes.getTopicArn())
.withProtocol("http")
.withEndpoint("http://" + InetAddress.getLocalHost().getHostAddress() + ":" + port);
service.subscribe(subscribeReq);
for (;;) {
// Wait for a message from HTTP server
Map<String, String> messageMap = messageQueue.take();
// Look for a subscription confirmation Token
String token = messageMap.get("Token");
if (token != null) {
// Confirm subscription
ConfirmSubscriptionRequest confirmReq = new ConfirmSubscriptionRequest()
.withTopicArn(createRes.getTopicArn())
.withToken(token);
service.confirmSubscription(confirmReq);
continue;
}
// Check for a notification
String message = messageMap.get("Message");
if (message != null) {
System.out.println("Received message: " + message);
}
}
}
public void getPropertyValues() throws IOException {
Properties prop = new Properties();
InputStream properties = getClass().getClassLoader().getResourceAsStream("SNS.properties");
prop.load(properties);
ACCESS_KEY = prop.getProperty("ACCESS_KEY");
SECRET_KEY = prop.getProperty("SECRET_KEY");
}
// HTTP handler
static class AmazonSNSHandler extends AbstractHandler {
// Handle HTTP request
public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch) throws IOException {
// Scan request into a string
Scanner scanner = new Scanner(request.getInputStream());
StringBuilder sb = new StringBuilder();
while (scanner.hasNextLine()) {
sb.append(scanner.nextLine());
}
// Build a message map from the JSON encoded message
InputStream bytes = new ByteArrayInputStream(sb.toString().getBytes());
Map<String, String> messageMap = new ObjectMapper().readValue(bytes, Map.class);
// Enqueue message map for receive loop
messageQueue.add(messageMap);
// Set HTTP response
response.setContentType("text/html");
response.setStatus(HttpServletResponse.SC_OK);
((Request) request).setHandled(true);
}
}
}
Your application needs to provide AWS credentials. These credentials can be obtained by several methods:
Create an IAM User and generate an Access Key and Secret Key. Include the credentials in a configuration file (it is not a good idea to put them in your application, since they could accidentally be published elsewhere).
If running the code on an Amazon EC2 instance, create an IAM Role and assign the role to the instance when it is launched. Credentials will then be automatically provided to applications running on that instance.
It is also necessary to assign permissions to the IAM User/Role. These permissions grant the right to call various AWS API calls. The fact that you receive an AuthorizationError suggests that the credentials in use do not have sufficient permissions.
See: Managing Access to Your Amazon SNS Topics
I have the following Javascript code to make a XMLHttpRequest to a server:
function createCORSRequest(method, url) {
var xhr = new XMLHttpRequest();
xhr.open(method, url, true);
return xhr;
}
function makeCorsRequest(word) {
var url = "https://localhost:8080/Method/Dictionary/" + word;
var xhr = createCORSRequest('GET', url);
xhr.onload = function() {
var responseText = xhr.responseText;
document.querySelector("#bar").innerHTML = responseText;
};
xhr.onerror = function() {
document.querySelector("#bar").innerHTML = 'Connection not allowed';
};
xhr.send();
}
makeCorsRequest("word");
At the server, I've got a REST structure (written using Jersey) similiar to:
#Path("/Dictionary")
public class Main{
public Definition returnDefinition(String word){
Definition definition = new Definition();
try{
...//play with Definition object
return definition;
}
catch(IOException IOE){
...
return definition;
}
}
#Path("{word}")
#GET
#Produces("text/xml ; charset=UTF-8") //"Definition" is already set as a XMLRoot element
public Definition main (#PathParam("word") String word){
return returnDefinition(word);
}
}
I try to make this request in two environments:
First environment: The JS code is inside a normal web page. In this case, I receive the following error after trying to make the request:
XMLHttpRequest cannot load http://localhost:8080/Method/Dictionary/word. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
Second environment: The JS code is inside a content script (that is itself inside a chrome extension). In this case, after about 30s of trying to make the request, I receive this:
Failed to load resource: net::ERR_TIMED_OUT
How to proceed?
EDIT: I've added a command to print something at the console in the beginning of the server method. And it is not printed. So, the requests are not reaching the server.
Origin 'null' happens if you are running the page as a file in the browser, using the file:// protocol, rather than set it up in a local webserver and access it using http://.
Hi i am creating client from my webservice. Client is generated successfully but when I call that from java code It throws following error:
Exception in thread "main" javax.xml.ws.WebServiceException: Failed to access the WSDL at: https://ebs-uat.corp.chartercom.com/csg_cter/2.06/orderdetailservice.asmx?wsdl. It failed with:
Server returned HTTP response code: 401 for URL: https://ebs-uat.corp.chartercom.com/csg_cter/2.06/orderdetailservice.asmx?wsdl.
at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.tryWithMex(RuntimeWSDLParser.java:151)
at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.parse(RuntimeWSDLParser.java:133)
at com.sun.xml.internal.ws.client.WSServiceDelegate.parseWSDL(WSServiceDelegate.java:254)
at com.sun.xml.internal.ws.client.WSServiceDelegate.<init>(WSServiceDelegate.java:217)
at com.sun.xml.internal.ws.client.WSServiceDelegate.<init>(WSServiceDelegate.java:165)
at com.sun.xml.internal.ws.spi.ProviderImpl.createServiceDelegate(ProviderImpl.java:93)
at javax.xml.ws.Service.<init>(Service.java:56)
at com.charter.enterprise.billing.csg.orderdetails.OrderDetailServicePort.<init>(OrderDetailServicePort.java:68)
at com.charter.enterprise.billing.csg.orderdetails.OrderDetailServiceClient.main(OrderDetailServiceClient.java:18)
Caused by: java.io.IOException: Server returned HTTP response code: 401 for URL: https://ebs-uat.corp.chartercom.com/csg_cter/2.06/orderdetailservice.asmx?wsdl
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1436)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:234)
at java.net.URL.openStream(URL.java:1010)
at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.createReader(RuntimeWSDLParser.java:793)
at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.resolveWSDL(RuntimeWSDLParser.java:251)
at com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser.parse(RuntimeWSDLParser.java:118)
... 7 more
It throws exception in first line when creating webservice port
DataServicePort dataServicePort = new DataServicePort();
My complete client class is:
public class OrderDetailServiceClient {
#WebServiceRef
private static OrderDetailServicePort orderDetailServicePort;
private static OrderDetailService orderDetailService;
public static void main(String[] args) {
orderDetailServicePort = new OrderDetailServicePort();
orderDetailService = orderDetailServicePort.getOrderDetailService();
// Add your code to call the desired methods.
System.out.println("Before calling method!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
verifyOrderDetail();
}
private static void verifyOrderDetail() {
BindingProvider prov = (BindingProvider) orderDetailService;
prov.getRequestContext().put(BindingProvider.USERNAME_PROPERTY,
"CHTR\tst_aopebstest");
prov.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY,
"T$t_#0p3B$t#sT");
orderDetailService = (OrderDetailService) prov;
VerifyOrderDetailRequest verifyOrderDetailRequest = new VerifyOrderDetailRequest();
VerifyOrderDetailResponse verifyOrderDetailResponse = orderDetailService
.verifyOrderDetail(verifyOrderDetailRequest, null);
}
}
I can hit in my browser. And it is also working in SoapUI. Where am I going wrong?
Any suggestion will be appreciated.
Thanks in advance.
It looks like you can't access that web service, have you tried accessing that web service through a web browser?
Good time.
Suppose there are 8 web-services in the one application. 5 of them require authorization (a client must to provide a JSESSIONID cookie and a corresponding session must not be invalidated), other 3 can be called without the jsessionid cookie. My naive solution is to write a servlet filter which intercepts requests and retrieve their pathInfos (all the services have the same url structure: /service/serviceSuffix). There is a enum which contains the serviceSuffix of each web service that requires authorization. When the request is retrieved the pathInfo is collected; if this pathInfo is contained in the enum and there is the corresponding valid session the request is sent ahead to the filter chain. Otherwise, an error is sent back to a client. After a while I've realized that it is needed to add the possibility to retrieve the wsdl and xsds for the concrete service. So that, two more check were added.
public class SecurityFilter implements Filter {
public static final String WSDL = "wsdl";
public static final String XSD = "xsd=";
/**
* Wittingly left empty
*/
public void init(FilterConfig filterConfig) throws ServletException {}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest servletRequest = (HttpServletRequest) request;
HttpServletResponse servletResponse = (HttpServletResponse)response;
String pathInfo = servletRequest.getPathInfo();
String queryString = servletRequest.getQueryString();
if (pathInfo != null && SecureWebServices.contains(pathInfo)) {
if (queryString != null && (queryString.equals(WSDL) || queryString.startsWith(XSD))) {
// wsdl or xsd is requested
chain.doFilter(request, response);
} else {
// a web service's method is called
HttpSession requestSession = servletRequest.getSession(false);
if (requestSession != null) { // the session is valid
chain.doFilter(request, response);
} else {
servletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
}
} else {
chain.doFilter(request, response);
}
}
/**
* Wittingly left empty
*/
public void destroy() {}
}
It seems that it is not very secure, because if the request's pathInfo is not in the enum, this request is passed on (just in case of some unexpected system calls).
Could you, please, suggest what to do, how to increase the security level. I want to build a configurable system (that is why I have the enum. It is possible just to add a path there to secure the web service and it is not required to duplicate the security code in the each web service). How to increase
Maybe I do not understand but.
jsessionid has nothink to do with security. you simply just get it.
Next I am not sure if you want authentication or authorization. The code as provided will not provide you with security features.
I suppose you are interested in authentication anyway. Security logic can be provided with standard web container features. Just send in authentication data in the header of request and you are done. web container can be configured to secure only selected resources (urls)