Although there's very similar post, it is unanswered.
My JavaFX app with WebSocket will
send user id、password to server
keep the session to let user do something like personal data management.
Learning from
Oracle WebSocket、
Tyrus 8.14 Client HTTP Authentication
I have:
#ClientEndPoint
public class loginEndPoint {
final ClientEndpointConfig cec = ClientEndpointConfig.Builder.create().build();
public static void main(String [] args) {
AuthConfig authConfig = AuthConfig.Builder.create().disableBasicAuth().build();
Credentials credentials = new Credentials("ws_user", "password");
client.getProperties().put(ClientProperties.AUTH_CONFIG, authConfig);
client.getProperties().put(ClientProperties.CREDENTIALS, credentials);
client.connectToServer(new Endpoint() {
#Override
public void onOpen(Session session, EndpointConfig config) {
try {
session.addMessageHandler((MessageHandler.Whole<String>) (String message) -> {
System.out.println("Received message: "+message);
messageLatch.countDown();
});
//let user do some data management
} catch (IOException e) {
System.out.println("Connect Fail.");
}
}
}, cec, new URI("ws://localhost/myApp/login"));
}
}
Is these code right to do the authentication? And where could I do the server side authentication on #ServerEndPoint?
#ServerEndpoint
public class loginServerEndPoint {
}
Thanks for help.
No, it is not necessary to use Tyrus as a server implementation.
On the server-side you should secure WebSocket in exactly the same way as you secure servlet or jsp in your servlet container, which can be slightly different from container to container (mapping users to roles).
Look at authentication example
Note that this example shows up how to make authenticated WebSocket request handshake with BASIC auth scheme, but your client code disables it explicitly, so probably you want to use DIGEST scheme.
Related
I'm trying build a SignalR proof of concept where two applications are involved; one is a web single-page application and the other one is a server-side RESTful web api. The technology/framework being used is ReactJs, ASP.NET Web API 2 (.NET Framework 4.6, NOT .NET Framework Core) and SignalR.
The Web API
This is how I have SignalR wired-up in the server application. When the application starts, I map SignalR to the application pipeline...
public static void ConfigureSignarlR(IAppBuilder app)
{
app.MapSignalR<ChatConnection>("/signalr", new Microsoft.AspNet.SignalR.HubConfiguration
{
EnableDetailedErrors = true
});
}
The ChatConnection class is an implementation of PersistentConnection that does nothing special...
public class ChatConnection : PersistentConnection
{
protected override Task OnReceived(IRequest request, string connectionId, string data)
{
return base.OnReceived(request, connectionId, data);
}
protected override Task OnConnected(IRequest request, string connectionId)
{
return base.OnConnected(request, connectionId);
}
public override Task ProcessRequest(HostContext context)
{
return base.ProcessRequest(context);
}
}
and then I have a very simple hub...
public class ChatHub : Hub
{
public void Send(string name, string message)
{
Clients.All.broadcastMessage(name, message);
}
}
The Client App
For the client application I'm using the #aspnet/signalr-client npm package...this is how I create and start the connection...
initialize = () => {
const hubCon = new HubConnection("http://api.domain/signalr");
hubCon.start()
.then(() => console.log("Connection established..."))
.catch(err => console.log(err))
}
Things to be noticed
Both the API and the client app are hosted on the same local IIS server but with different host names (using host files)
When using the browser to navigate to http://api.domain/signalr/hubs, I get a 400 (Bad Request) response when the message following message Protocol error: Unknown transport.
When attempting to connect from the client app, I get the same error message
The ProcessRequest method is the only one that gets hit when debugging the ChatConnection class
Question(s)
What did I miss here? Or how can I get this PoC to work?
The question is quite broad because I seriously have no clue of what's going on here
After a bit of digging and reading through SignalR documentation I realized that I was doing everything wrong. Basically, SignalR implements two different connection patterns:
Hubs: a high-level API built on top of the Persistent connection API
Persistent connections
A client cannot communicate with a persistent connection endpoint using a Hub proxy (or at least not the way I was doing it). So, what I did was:
Kept the PersistentConnection but overrided the OnReceived method so it can broardcast to all clients
protected override async Task OnReceived(IRequest request, string connectionId, string data)
{
await Connection.BroadCast("message to broadcast");
}
Removed the "signalr\hubs" script reference because it's not needed
Registered the connection on start up (server-side)
app.MapSignalR<ChatConnection>("/chat");
Finnaly, on the client side, initialize the connection and register all necessary callbacks
this.connection = window.$.connection(process.env.REACT_APP_API_BASE_URI + "/chat");
this.connection.logging = true;
this.connection.received((data) => {
console.log("Received some data:")
console.log(data)
});
this.connection.start(() => {
console.log("Connection opened")
console.log("connectionId = " + this.connection.id)
});
What is the best way to manage a user session in a Google App Engine application? Ideally I'd like to keep my application stateless and not save any user related data in memory, however I'm also afraid to send user credentials of the network on every request (not to mention authenticating the user on every request would require a call to the Datastore which costs money).
I checked out google's OAuth 2.0 solution but from my understanding it helps if my application wants to connect to any of the google APIs and needs permission from the client to access his google account.
Is there a go to way for managing user session? The most common scenario is to know which user initiated this request without having to send the userId as a request parameter.
Please note that we are not using third party providers. The user registers himself to our page normally and has a custom account. I'm not looking for tools that help integrate authentication with third party services. Otherwise I'd be using google's OAuth 2.0 or similar API
You can Always implement Authenticator Interface.
public class MyAuthenticator implements Authenticator {
#Override
public User authenticate(HttpServletRequest request) {
HttpSession session = request.getSession(false);
//
return null;// if not authenticated, otherwise return User object.
}
}
// Endpoints class.
#Api(name = "example", authenticators = { MyAuthenticator.class })
public class MyEndpoints {
public Profile getProfile(User user) {
if (user == null) {
throw new UnauthorizedException("Authorization required");
}
return new Profile(user.getEmail(), "displayName");
}
// store this class somewhere in models
public class Profile {
private String email;
private String displayName;
public Profile(String email, String displayName) {
this.email = email;
this.displayName = displayName;
}
public String getEmail() {
return email;
}
public String getdisplayName() {
return displayName;
}
}
}
Use the HttpServletRequest object to implement classic session based login or use your own custom header. Well that depends on your case. Return null when not authenticated and return User object when authenticated. Also implement some kind of encryption on both sides(client and server), so as to stop someone having the session key to access your api.
I'm following a Udemy course in attempt to build my first Spring Boot application. Rather than using Spring Security, they are using JJWT to implement stateless authentication.
The front end is in Angular, and because it runs on it's own server, CORS is used to open everything up so that the Angular app can hit the Java backend API.
I'm worried that this will open the door to CSRF or other security holes.
After some digging I found similar code to what the Udemy course is using here, but I don't know enough about security to know if it's enough.
The code in question is as follows:
Filter:
public class JwtFilter extends GenericFilterBean {
#Override
public void doFilter(final ServletRequest req,
final ServletResponse res,
final FilterChain chain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) req;
final String authHeader = request.getHeader("Authorization");
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
throw new ServletException("Missing or invalid Authorization header.");
}
final String token = authHeader.substring(7); // The part after "Bearer "
try {
final Claims claims = Jwts.parser().setSigningKey("secretkey")
.parseClaimsJws(token).getBody();
request.setAttribute("claims", claims);
}
catch (final SignatureException e) {
throw new ServletException("Invalid token.");
}
chain.doFilter(req, res);
}
Cors Config:
#Configuration
public class CorsConfig {
#Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true); //usually want this
config.addAllowedOrigin("*");//not sure if secure?
config.addAllowedHeader("*");
config.addAllowedMethod("GET");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
Filter added to main application class:
#SpringBootApplication
public class BackendApplication {
#Bean
public FilterRegistrationBean jwtFilter() {
final FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter((Filter) new JwtFilter());
registrationBean.addUrlPatterns("/rest/*");
return registrationBean;
}
public static void main(String[] args) {
SpringApplication.run(BackendApplication.class, args);
}
}
So is this sort of setup secure enough to be used in production code, or is a more robust solution needed?
Or is there a better way entirely to do stateless authentication? If they were both running on the same domain I wouldn't need CORS right?
Do not use JWT for security purposes. JWT contains information other than random keys which should not be present in the authorisation header. Although we can sign a JWT token, yet we should avoid it. Instead save the extra information in the database and query it whenever you receive the token at server side to check authenticity of the token. Also, the algorithm type none can prove to be a security disaster if exploited by an attacker. Use simple random string as token. Fairly simple and more secure. Confidential information resides in database and not in the token and we all know that databases are very secure.
We use Resteasy to communicate between multiple backend servers & we want to lock this down so not just anyone can attach a client or browser to the restlet server.
We're using Resteasy 3.04 and as our backend services are numerous but very light-weight an embeddded TJWS webserver.
Example Server code:
public class RestEasySSLBasicAuthenticationServer {
static TJWSEmbeddedJaxrsServer webServer;
static class BasicAthenticationSecurityDomain implements SecurityDomain {
#Override
public Principal authenticate(String aUsername, String aPassword) throws SecurityException {
System.out.println("User:" + aUsername + " Password" + aPassword);
if (aPassword.equals("password") == false) {
throw new SecurityException("Access denied to user " + aUsername);
}
return null;
}
#Override
public boolean isUserInRoll(Principal aUsername, String aRole) {
// No role based checks so return true
return true;
}
}
public static void main(String[] args) throws Exception {
// Create embedded TJWS web server
webServer = new TJWSEmbeddedJaxrsServer();
// Set up SSL connections on server
webServer.setSSLPort(8081);
webServer.setSSLKeyStoreFile("K:\\source\\RestEasyTest\\server_localhost.jks");
webServer.setSSLKeyStorePass("krypton");
webServer.setSSLKeyStoreType("JKS");
// Add basic HTTP authentication to the server
webServer.setSecurityDomain( new BasicAthenticationSecurityDomain() );
// Add the restlet resource
webServer.getDeployment().getActualResourceClasses().add(PlayerResource.class);
// Start the web server
webServer.start();
// Run until user presses a key
System.out.print("Web server started. Press a key to stop...");
System.in.read();
// Stop the web server
webServer.stop();
}
}
Example client code:
public class RestEasySSLBasicAuthenticationClient {
public static void main(String[] args) throws Exception {
// Set up the keystore
System.setProperty("javax.net.ssl.keyStore", "K:\\source\\RestEasyTest\\client_localhost.jks");
System.setProperty("javax.net.ssl.keyStoreType", "JKS");
System.setProperty("javax.net.ssl.keyStorePassword", "krypton");
// Create a new Restlet client
Client restletClient = ClientBuilder.newClient();
// *** Even WITHOUT these credentitials we can access the restlet
// restletClient.register(new BasicAuthentication("username", "password"));
// Set up the restlet request target.
WebTarget request = restletClient.target("https://localhost:8081/player/{id}");
request = request.resolveTemplate("id", Long.valueOf(1));
// Build the restlet request
Invocation invocation = request.request("application/xml").buildGet();
// Call the restlet and get returned object
Player result = invocation.invoke( Player.class );
System.out.println(result.toString());
}
}
Using the test client and a registered authentication filter works and as expected I can a 401 access error if I get the password incorrect.
However if no authentication is registered at the client then the server never calls the SecurityDomain check and access is allowed.
How do I enforce a login at the server?
You can ensure all users are authenticated by enabling security on the embedded TJWS web server.
webServer.getDeployment().setSecurityEnabled(true);
I am trying to read the mails from the exchange server 2010 , however sometimes the connection got established , but remaining times program gives below exception:
javax.mail.AuthenticationFailedException: LOGIN failed
The code is working fine with the exchange server 2007 . But from the time mailbox has been migrated to 2010, the program is behaving in this fashion only.
I have also tried with several options available on net, but nothing is working. I am using javamail-1.4.4 API version . Here is the piece of code through which I am just trying to connect to the mailbox .
public class ReadMail {
static Store store=null;
static String host="";
static String username="";
static String password="";
public static void main(String[] arg) throws Exception{
try{
Session session;
username = "username";
password = "password";
host = "hostname";
Properties props = System.getProperties();
props.setProperty("mail.smtp.auth","true");
session = Session.getInstance(props,
new ExchangeAuthenticator(username, password));
Store st = session.getStore("imaps");
st.connect(host,username, password);
System.out.println("Connected");
}
catch (Exception e){
e.printStackTrace(System.out);
}
}
}
public class ExchangeAuthenticator extends Authenticator {
String user;
String pw;
public ExchangeAuthenticator (String username, String password)
{
super();
this.user = username;
this.pw = password;
}
public PasswordAuthentication getPasswordAuthentication()
{
return new PasswordAuthentication(user, pw);
}
}
I also face same problem in my code i set two properties in my code
disable plain test and enable NTLM
props.setProperty("mail.imap.auth.plain.disable","true");
props.setProperty("mail.imap.starttls.enable", "true");
now my code able to connect with exchange server
read it
https://forums.oracle.com/forums/thread.jspa?threadID=1587688
Perhaps the configuration of the server has changed and it's no longer accepting your credentials, or no longer supporting any of the login methods that JavaMail supports.
Turn on session debugging and examine the protocol trace. It should provide some clues as to why it's failing.
You might also want to upgrade to JavaMail 1.4.5, which has built-in support for NTLM authentication, which you might need.
Even though your credentials are OK, the new server might not accept your login method. For instance, the new server might not allow "Plain" authentication.
The debugging info should show which authentication methods are accepted.