I am migrating some Java EE modules from Spring to EJB and are now facing the problem that I need some sort of pre-authentication prior to calling a service method.
The problem is actually quite easy. A call comes in from an internal protocol handler (some thread started the proprietary protocol handler and received requests using a custom TCP protocol). Not this connection already authenticated the user and wants to call a service method next. This service method requires a principal information (user name) for processing.
So in Spring we simply pushed the SecurityContext to the local thread and removed it when the call was done.
Protocol Handler -> Set SecContext -> Call -> Remove SexContext -> End
Is there anything similar to that in Java EE/JBoss? I know there are "#RunAs" constructs but I don't know if they can be used programmatically. Or is there a way to "log in" using the JAAS LoginContext class? But how do I configure JAAS then?
If this is purely a matter of getting an identity into the JAAS context, you should be able to do something like this:
final String username; // get this from somewhere
Princpal principal = new Principal() {
public String getName() {
return username;
}
};
Subject subject = new Subject(true, Collections.singleton(principal), Collections.emptySet(), Collections.emptySet());
Subject.doAs(subject, new PrivilegedAction<Void>() {
public Void run() {
// do your method call here
}
});
Note that you can return a value from the PrivilegedAction by binding it to a type other than Void, and throw an exception by implementing PrivilegedExceptionAction instead.
Obviously if you have a more sophisticated idea of what a principal is, you could use that (implementing toString, hashCode, and equals would be a good idea).
Related
I am writing an OSGI service component in AEM.
I want to fetch current domain name in the activate method of the service component.
Currently, I'm writing a construct method, to get request from referring class/service/model/servlet to initialize the 'request' class object and using this request object to get the server name
private SlingHttpServletRequest request;
private String domainName;
#Override
public void construct(final SlingHttpServletRequest request) {
this.request = request;
}
#Override
public void setDomainName(){
this.domainName = request.getServerName();
}
And this.domainName is used in multiple service method implementations.
So, I have to call 2 extra service method,
Construct - to initialize global request object
setDomainName - to initialize domainName global object to be used across all the other service methods
Is there anyway to get domainName in activate method, so that i do not have to call the above two methods in order to use the service.
Note:- I cannot create an OSGI config for domain name, as this domain name is already being used as key property to identify the OSGI config of a given factory
Since AEM publish servers might be used for several domains, there is no way to "know" the right domain without getting the request. There might also be some magic being done by the web server and the CDN before the request is even reaching AEM.
On top of that, the activate method is not called each time the service is used, since those components are used multiple times.
So I think no, there is no way to guess what the domain of the next incoming request will be when the component is activated.
BR,
Oliver
To add to #OliverGeberts answer, this information can be added to the content (i.e. page properties of the language root) or some sort of tenant configuration.
I've a scheduler class and another class a custom http client.
The scheduler is initialized on application start up and does the work in background for example querying a service (url) every 30 seconds and write the data to logs.
The http client is created with the url as well.
The url can change anytime so I need to make sure whenever it is the both log scheduler and http client are reinitialized with new url.
public class LogScheduler {
public log() {
synchronized(globallock) {
String url = getUrl();
//log some activity
}
}
}
We have another scheduler which is looking for new url every 30 minutes.
public class UrlScheduler {
private volatile String url;
public void check() {
String url = service.getNewUrl();
if(url!=this.url) {
synchronized(globallock) {
this.url=url;
reinitialize http client
}
}
}
public String getUrl(){
return url;
}
}
Right now I'm using global lock to make sure the log scheduler sees the value as soon it is changed by url scheduler. I really don't like the idea of using global lock as it breaks encapsulation along with other issues.
How could I change my set up to to reinitialize log scheduler and http client as soon the url is changed and sync them as it is changed in order ? I would like to avoid re-initialization if url hasn't changed.
Also how could I block the ui thread using http client if the url is being updated when the request was made.
This is a spring application.
Let me know if it is not clear and I'm happy to provide more details.
Working with limited information, if anything wouldn't work let me know and I'll change it.
To me the simplest thing is to decouple the HTTPClient from anything that may need it. Decoupling the client means you don't need to deal with synchronization issues in classes that are focused on other things(e.g. logging or pinging the service)
Here's a diagram. https://i.imgur.com/PWsXx2G.png
It seems like you'd be changing very little. The main differences is you'd create a wrapper for your HTTPClient, that way in the client you could synchronize it to make sure the HTTPClient is always the correct one.
An example wrapper, don't use this as it's very simple
public class HTTPClientProxy{
private final Object syncLock = new Object();
private HTTPClient client;
public HTTPClient getClient(){
synchronized(syncLock){
return client;
}
}
public void updateClient(URL url){
synchronized(syncLock){
client = new HTTPClient(url);
}
}
}
One potential issue, and one that I'm not sure about. Is if you have multiple services, and they all are bundler (e.g. are linked and need to use the same URL). Then you'll need to have something else on that side, so you can ensure they all use the same client. However this would be a good start as it stops you from worrying about getting bad data from the HTTPClient and moves that functionality into the proxy class.
I believe the observer pattern is useful here.
The URL scheduler, or whatever class is responsible for the knowing the state of the URL at any given point (called the subject), would maintain a list of observers (the other objects which wish to be notified when the URL changes), being the log scheduler and the other http client.
The observers simply implement an interface providing a notification function which accepts the new URL as a parameter. Whenever the url changes, the subject notifies everyone in its list of observers by calling their notification functions.
This makes it so that the log scheduler and other http client are only notified when the URL changes, and they are notified immediately.
If you wished to decouple the observers and subjects (generally more useful when there are many observers observing many subjects), you could build an event manager using a mediator pattern. However, this would probably be overkill given your requirements.
SimpUserRegistry lets you retrieve the details of all authenticated Stomp sessions, is there any such class that will let me iterate over anonymous user sessions?
Like howie described in his answer only non anonymous users will be added to the SimpUserRegistry.
But if you really want to add anonymous users also you just have to sub-class the DefaultHandshakeHandler class and override the determineUser method like stated in the Spring Doc for Version 5.0.0.M1 - Chapter 22. This should also be working for 5.1.5.Release which you are currently on when using Spring Boot 2.1.3.RELEASE:
In some cases it may be useful to assign an identity to a WebSocket session even when the user has not been formally authenticated. For example, a mobile app might assign some identity to anonymous users, perhaps based on geographical location. The do that currently, an application can sub-class DefaultHandshakeHandler and override the determineUser method. The custom handshake handler can then be plugged in (see examples in Section 22.2.4, “Deployment Considerations”).
Here is an answer (Spring websockets without principal) which shows you how you can achieve to create an AnonymousPrincipal and determine it within the custom handshake handler.
And at last you have to add your an instance of your custom handshake handler to your registered endpoint but this is depending on whether you use STOMP or not.
Following are some of the code snippets from StompSubProtocolHandler -
The handleMessageFromClient method adds the user to the stompAuthentications map and publishes a SessionConnectEvent event -
public void handleMessageFromClient(WebSocketSession session, WebSocketMessage<?> webSocketMessage, MessageChannel outputChannel) {
//...
SimpAttributesContextHolder.setAttributesFromMessage(message);
boolean sent = outputChannel.send(message);
if (sent) {
if (isConnect) {
Principal user = headerAccessor.getUser();
if (user != null && user != session.getPrincipal()) {
this.stompAuthentications.put(session.getId(), user);
}else{
//TODO try to handle here for anonymous user
}
}
if (this.eventPublisher != null) {
if (isConnect) {
publishEvent(new SessionConnectEvent(this, message, getUser(session)));
}
//...
I think you have to Check this socure code StompSubProtocolHandler, and customize it.
I have implemented a custom HttpAuthenticationMechanism subclass to provide authentication using the Soteria/Java EE Security framework. I've got authentication working just fine. However, I've noticed that when I call HttpMessageContext.setRegisterSession(String, Set<String>) to create a Java EE Session, the behavior is not what I would expect. I am expecting that the authenticated identity be associated with the web Session, and my AuthenticationMechanism's validateRequest(HttpServletRequest req, HttpServletResponse res, HttpMessageContext ctx) method would not be called on subsequent requests. What I am observing, however, is that validateRequest() is called on every request, even if the user has already authenticated successfully.
I am able to get the behavior I want using the #AutoApplySession annotation on my AuthenticationMechanism class, but that is not the behavior I want. I'd like to choose whether or not to create a session based on the type of credential provided.
Is my understanding of the setRegisterSession() method incorrect? Or is this a bug within Soteria?
#AutoApplySession is the new way to do this in Soteria (JSR 375). If it does not suit your needs (as you need to either remember the authenticated identity or re-authenticate for all requests during the same HTTP session based on some other credential info), validateRequest method will still be called, regardless of whether you call the HttpMessageContext'ssetRegisterSession method or not. HttpMessageContext.setRegisterSession will make the container remember the credentials but will not reuse them automatically, you still need to make the container reuse the authentication identity by doing the same thing Soteria's AutoApplySessionInterceptor does. So in your class which implements HttpAuthenticationMechanism you should add the following code before your actual authentication logic is performed in the validateRequest method:
Principal userPrincipal = request.getUserPrincipal();
if (userPrincipal != null) {
httpMessageContext.getHandler().handle(new Callback[] {
new CallerPrincipalCallback(httpMessageContext.getClientSubject(), userPrincipal) }
);
return AuthenticationStatus.SUCCESS;
}
Also, see this answer by Arjan Tijms. Although it's about JASPIC not Soteria, but in this case I think it's relevant.
Hope this helps.
I thing you're following the incorrect source you've look at this IMPLEMENTATION.
/* (non-Javadoc)
* #see javax.security.authenticationmechanism.http.HttpMessageContext#setRegisterSession(java.lang.String, java.util.Set)
*/
#Override
public void setRegisterSession(String username, Set<String> groups) {
Jaspic.setRegisterSession(messageInfo, username, groups);
}
Under the library location:
import org.glassfish.soteria.mechanisms.jaspic.Jaspic;
From the mechanisms.
This question already has an answer here:
How to invoke a REST service
(1 answer)
Closed 7 years ago.
I have this web service http://qa-takehome-creyzna.dev.aetion.com:4440 that I would like to test. I have the authentication details (username and password) and the service has the following end points: /login, /user/, /user/{id} and /user/search. For all endpoints other than /login an authorization token needs to be passed as an HTTP Header.
The service exposes a login endpoint ( /login) which takes a POST request with two parameters: username and password. Following a successful login, an authentication token will be returned which must be used to make additional requests to the service. For example,if the request is as following,
{
"username": "admin",
"password": "admin"
}
It may return { "token": "1234-0009-999" } and this token will required for making additional request.
I will need to authenticate the web service, create 10 users and then, retrieve that information to validate the users was created correctly. I would like to develop a test plan and implement in Eclipse. How can I get started ?
A web service is basically an extension of the Java Servlet, where the input is processed a bit more and the output is rarely an HTML page.
Netbeans has an excellent tutorial on how to stand up a web service, and if you follow it, you can have a basic web service running within the hour.
https://netbeans.org/features/java-on-server/web-services.html
Don't be fooled by thinking that you must use one IDE (I like netbeans, but others don't) or another. The fancy GUI tools are just writing plain Java classes that might use other plain Java facilities (like JAXB if using XML, etc).
A web service is not much more than a web server that accepts particular kinds of requests, and responds with particular kinds of responses. In Java, web servers are made easier to use by leveraging Servlets. The internal contents of the Servlet will look like
Unpack the request
Validate the request is complete, report an error response if not
Act on the reqeust
Generate a response in the appropriate format
Send the response back as the reply.
--- Edited in response to request ---
Sorry, It seemed too obvious to me. Let me fill in the gaps. Sorry for glossing over the details.
public class MockHttpServletRequest implements HttpServletRequest {
#Override
public String getAuthType() {
throw new UnsupportedOpertationException("unexpected method use");
}
#Override
public String getContextPath() {
throw new UnsupportedOpertationException("unexpected method use");
}
... repeat for all methods ....
}
public class ItemRequestWithBadEncoding extends MockHttpServletRequest {
#Override
public String getMethod() {
return "GET";
}
#Override
public String getHeader(String name) {
if ("content-type".equals(name)) {
return "text/plain-ish"; // this is not a mime-type
}
throw new IllegalArgumentException(String.format("this mock doesn't support %s", name);
}
... fill out the rest of the required request details ...
}
public class CapturingServletResponse implements HttpServletRespose {
private final ArrayList<Cookie> cookies = new ArrayList<Cookie>();
#Override
public void addCookie(Cookie cookie) {
cookies.add(cookie);
}
public List<Cookie> getCookies() {
return Collections.unmodifiableList(cookies);
}
... override other methods and capture them into per-instance fields
with ability to return unmodifiable references or copies to them ...
}
Now back in the testing framework
#Test
public void testItemFetch() {
try {
MockRequest request= ItemRequestWithBadEncoding();
CapturingServletResponse response = new CapturingServletResponse();
Servlet itemRequestServlet = new ItemRequestServlet();
itemRequestServlet.service(request, response);
Assert.assertEquals("unexpected cookies in response", 0, response.getCookies().size());
... other asssertations ....
} catch (Exception e) {
Assert.assertFail(String.format("unexpected exception: %s", e.getMessage());
}
}
Depending on what items you care about, and how much work you need to put into it, you can then flesh out the needed parts of the capture and perhaps parameterize and refine the way you construct your input handling.
Look into spring frameworks.
They go well with other testing frameworks like Mockito and Junits.
Use something like SpringMVCTest or SpringRestAssured, note RestAssured would let you write integration tests.
Read this and this