Skip to content

Commit

Permalink
Security updates: Create new security module, use that module in the …
Browse files Browse the repository at this point in the history
…http & xenia modules, and remove requirement for web sessions; refactor Realm API and DB-based realm implementation
  • Loading branch information
cpurdy authored and Gene Gleyzer committed Nov 27, 2024
1 parent a22933c commit ccd521a
Show file tree
Hide file tree
Showing 79 changed files with 5,489 additions and 2,908 deletions.
4 changes: 2 additions & 2 deletions doc/bnf.x
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ ArgumentList
"(" Arguments-opt ")"

Arguments
Argument
Arguments "," Argument
Argument ","-opt
Arguments "," Argument ","-opt

Argument
NamedArgument-opt ArgumentExpression
Expand Down
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ xdk-json = { group = "org.xtclang", name = "lib-json", version.ref = "xdk" }
xdk-jsondb = { group = "org.xtclang", name = "lib-jsondb", version.ref = "xdk" }
xdk-net = { group = "org.xtclang", name = "lib-net", version.ref = "xdk" }
xdk-oodb = { group = "org.xtclang", name = "lib-oodb", version.ref = "xdk" }
xdk-sec = { group = "org.xtclang", name = "lib-sec", version.ref = "xdk" }
xdk-web = { group = "org.xtclang", name = "lib-web", version.ref = "xdk" }
xdk-webauth = { group = "org.xtclang", name = "lib-webauth", version.ref = "xdk" }
xdk-webcli = { group = "org.xtclang", name = "lib-webcli", version.ref = "xdk" }
Expand Down
5 changes: 3 additions & 2 deletions javatools/src/main/java/org/xvm/asm/Annotation.java
Original file line number Diff line number Diff line change
Expand Up @@ -194,18 +194,19 @@ public Constant[] getParams()
*
* @param aParams the new parameters (may include default parameter values)
*/
public void resolveParams(Constant[] aParams)
public Annotation resolveParams(Constant[] aParams)
{
if (!Arrays.equals(aParams, m_aParams))
{
if (getPosition() >= 0)
{
// we must never change the hashCode/equality for already registered constants
throw new IllegalStateException("Annotation has already been registered: " + this);
return getConstantPool().ensureAnnotation(getAnnotationClass(), aParams);
}

m_aParams = aParams;
}
return this;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4035,7 +4035,7 @@ protected void layerOnProp(
if (propBase == null && propContrib.isOverride())
{
log(errs, Severity.ERROR, VE_PROPERTY_OVERRIDE_NO_SPEC,
typeContrib.getValueString(), propContrib.getName());
typeContrib.removeAccess().getValueString(), propContrib.getName());
}

// the property is stored both by its absolute (fully qualified) ID and its nested
Expand Down
23 changes: 14 additions & 9 deletions javatools/src/main/java/org/xvm/compiler/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -1855,7 +1855,7 @@ List<AstNode> parseConditionList()
{
List<AstNode> list = new ArrayList<>(4);
list.add(parseCondition(false));
while (match(Id.COMMA) != null)
while (match(Id.COMMA) != null && !peek(Id.R_PAREN))
{
list.add(parseCondition(false));
}
Expand All @@ -1864,14 +1864,14 @@ List<AstNode> parseConditionList()

AstNode parseCondition(boolean fNegated)
{
if (!fNegated && peek(Id.NOT) != null)
if (!fNegated && peek(Id.NOT))
{
// test for a negated conditional assignment
Token tokNot = peek();
Token tokNot = null;
AssignmentStatement stmtAsn = null;
try (SafeLookAhead attempt = new SafeLookAhead())
{
expect(Id.NOT);
tokNot = expect(Id.NOT);
if (match(Id.L_PAREN) != null)
{
AstNode stmtPeek = parseCondition(true);
Expand Down Expand Up @@ -2440,12 +2440,17 @@ MultipleLValueStatement peekMultiVariableInitializer()
listLVals.add(LVal);
}

Token comma = match(Id.COMMA);
if (!fFirst && match(Id.R_PAREN) != null)
{
return new MultipleLValueStatement(listLVals);
}

expect(Id.COMMA);
if (comma == null)
{
// comma is required
expect(Id.COMMA);
}
}
}

Expand Down Expand Up @@ -5463,8 +5468,8 @@ List<TypeExpression> parseParameterTypeList(boolean required)
* "(" Arguments-opt ")"
*
* Arguments
* Argument
* Arguments "," Argument
* Argument ","-opt
* Arguments "," Argument ","-opt
*
* Argument
* NamedArgument-opt ArgumentExpression
Expand Down Expand Up @@ -5880,7 +5885,7 @@ protected Token peek()
*
* @return true iff the next token matches
*/
protected Boolean peek(Token.Id id)
protected boolean peek(Token.Id id)
{
return peek().getId() == id;
}
Expand All @@ -5891,7 +5896,7 @@ protected Boolean peek(Token.Id id)
*
* @return true iff the next token is either an identifier or the "_" token
*/
protected Boolean peekNameOrAny()
protected boolean peekNameOrAny()
{
Token.Id id = peek().getId();
return id == Id.IDENTIFIER || id == Id.ANY;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ else if (exprNew instanceof LambdaExpression exprLambda)
}
}
exprOld.log(errs, Severity.ERROR, Compiler.CONSTANT_REQUIRED);
return;
}
}

Expand All @@ -372,7 +373,7 @@ else if (exprNew instanceof LambdaExpression exprLambda)
}
}

anno.resolveParams(aconstArgs);
m_anno = anno.resolveParams(aconstArgs);
}
}

Expand Down
7 changes: 3 additions & 4 deletions javatools/src/main/java/org/xvm/runtime/ClassTemplate.java
Original file line number Diff line number Diff line change
Expand Up @@ -970,7 +970,7 @@ else if (field.isTransient())
private int getInjectedProperty(Frame frame, GenericHandle hThis, PropertyConstant idProp,
int iReturn)
{
TypeInfo info = hThis.getType().ensureTypeInfo();
TypeInfo info = hThis.getType().ensureAccess(Access.PRIVATE).ensureTypeInfo();
PropertyInfo prop = info.findProperty(idProp, true);
Annotation anno = prop.getRefAnnotations()[0];
Constant[] aParams = anno.getParams();
Expand All @@ -983,15 +983,14 @@ private int getInjectedProperty(Frame frame, GenericHandle hThis, PropertyConsta
if (Op.isDeferred(hOpts))
{
return hOpts.proceed(frame, frameCaller ->
getInjectedProperty(frameCaller, hThis, idProp, iReturn));
getInjectedProperty(frameCaller, hThis, idProp, iReturn));
}

ObjectHandle hValue = frame.getInjected(sResource, prop.getType(), hOpts);
if (hValue == null)
{
return frame.raiseException(
xException.illegalState(frame, "Unknown injectable resource \"" +
prop.getType().getValueString() + ' ' + sResource + '"'));
xException.unknownInjectable(frame, prop.getType(), sResource));
}

// store off the value (even if deferred), so a concurrent operation wouldn't "double dip"
Expand Down
4 changes: 2 additions & 2 deletions javatools/src/main/java/org/xvm/runtime/Frame.java
Original file line number Diff line number Diff line change
Expand Up @@ -312,9 +312,9 @@ public Frame createWaitFrame(ObjectHandle[] ahFuture, int[] aiReturn)
int cReturns = ahFuture.length;

List<CompletableFuture> listFutures = new ArrayList<>(cReturns);
for (int i = 0; i < cReturns; i++)
for (ObjectHandle handle : ahFuture)
{
if (ahFuture[i] instanceof FutureHandle hFuture)
if (handle instanceof FutureHandle hFuture)
{
listFutures.add(hFuture.getFuture());
}
Expand Down
15 changes: 4 additions & 11 deletions javatools/src/main/java/org/xvm/runtime/NativeContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -384,16 +384,6 @@ private void initResources(ConstantPool pool)
TypeConstant typeServer = templateServer.getCanonicalType();
addResourceSupplier(new InjectionKey("server", typeServer), templateServer::ensureServer);

// +++ web:Authenticator (Nullable|Authenticator)
ModuleConstant moduleWeb = pool.ensureModuleConstant("web.xtclang.org");
TypeConstant typeAuthenticator = pool.ensureTerminalTypeConstant(
pool.ensureClassConstant(pool.ensurePackageConstant(moduleWeb, "security"), "Authenticator")).
ensureNullable();
// the NativeContainer can only supply a trivial result; anything better than that must be
// done naturally by a container that hosts the calling container
addResourceSupplier(new InjectionKey("providedAuthenticator", typeAuthenticator),
(frame_, opts_) -> xNullable.NULL);

// +++ mgmt.Linker
xContainerLinker templateLinker = xContainerLinker.INSTANCE;
TypeConstant typeLinker = templateLinker.getCanonicalType();
Expand Down Expand Up @@ -767,7 +757,10 @@ public ObjectHandle getInjectable(Frame frame, String sName, TypeConstant type,
InjectionKey key = f_mapResourceNames.get(sName);
if (key == null)
{
return null;
// for "Nullable" types the NativeContainer can only supply a trivial result;
// anything better than that must be done naturally by a container that hosts the
// calling container
return type.isNullable() ? xNullable.NULL : null;
}

// check for equality first, but allow "congruency" or "duck type" equality as well
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -357,16 +357,18 @@ private void configureBinding(HttpServerHandle hServer, ObjectHandle hBinding) {
}

/**
* Implementation of "void addRouteImpl(String hostName, HandlerWrapper wrapper,
* KeyStore keystore, String? tlsKey=Null)" method.
* Implementation of "void addRouteImpl(String hostName, UInt16 httpPort, UInt16 httpsPort,
* HandlerWrapper wrapper, KeyStore keystore, String? tlsKey=Null)" method.
*/
private int invokeAddRoute(Frame frame, HttpServerHandle hServer, ObjectHandle[] ahArg)
{
String sHostName = ((StringHandle) ahArg[0]).getStringValue();
ServiceHandle hWrapper = (ServiceHandle) ahArg[1];
KeyStoreHandle hKeystore = ahArg[2] instanceof KeyStoreHandle hK ? hK : null;
String sTlsKey = ahArg[3] instanceof StringHandle hS ? hS.getStringValue() : null;
Router router = hServer.getRouter();
String sHostName = ((StringHandle) ahArg[0]).getStringValue();
int nHttpPort = (int) ((JavaLong) ahArg[1]).getValue();
int nHttpsPort = (int) ((JavaLong) ahArg[2]).getValue();
ServiceHandle hWrapper = (ServiceHandle) ahArg[3];
KeyStoreHandle hKeystore = ahArg[4] instanceof KeyStoreHandle hK ? hK : null;
String sTlsKey = ahArg[5] instanceof StringHandle hS ? hS.getStringValue() : null;
Router router = hServer.getRouter();

if (hKeystore != null)
{
Expand Down Expand Up @@ -401,7 +403,7 @@ private int invokeAddRoute(Frame frame, HttpServerHandle hServer, ObjectHandle[]
}

RequestHandler handler = createRequestHandler(frame, hWrapper, hServer);
RouteInfo route = new RouteInfo(handler, hKeystore, sTlsKey);
RouteInfo route = new RouteInfo(handler, nHttpPort, nHttpsPort, hKeystore, sTlsKey);

if (hServer.getHttpServer().getAddress().getHostName().equals(sHostName))
{
Expand Down Expand Up @@ -430,19 +432,19 @@ private boolean isValidPair(KeyStoreHandle hKeystore, String sName)
*/
private int invokeReplaceRoute(Frame frame, HttpServerHandle hServer, ObjectHandle[] ahArg, int iResult)
{
StringHandle hHostName = (StringHandle) ahArg[0];
ServiceHandle hWrapper = (ServiceHandle) ahArg[1];
Router router = hServer.getRouter();
String sHostName = hHostName.getStringValue();
RouteInfo info = router.mapRoutes.get(sHostName);
String sHostName = ((StringHandle) ahArg[0]).getStringValue();
ServiceHandle hWrapper = (ServiceHandle) ahArg[1];
Router router = hServer.getRouter();
RouteInfo info = router.mapRoutes.get(sHostName);

if (info == null)
{
return frame.assignValue(iResult, xBoolean.FALSE);
}

RequestHandler handler = createRequestHandler(frame, hWrapper, hServer);
router.mapRoutes.put(sHostName, new RouteInfo(handler, info.hKeyStore, info.sTlsKey));
router.mapRoutes.put(sHostName,
new RouteInfo(handler, info.nHttpPort, info.nHttpPort, info.hKeyStore, info.sTlsKey));
return frame.assignValue(iResult, xBoolean.TRUE);
}

Expand Down Expand Up @@ -499,13 +501,15 @@ private int invokeGetReceivedFromAddress(Frame frame, HttpContextHandle hCtx, in
*/
private int invokeGetHostInfo(Frame frame, HttpContextHandle hCtx, int[] aiResult)
{
String sHost = getHostName(hCtx.f_exchange);
int nPort = getHostPort(hCtx.f_exchange);
HttpExchange exchange = hCtx.f_exchange;
String sHost = exchange.getRequestHeaders().getFirst("Host");
String sName = extractHostName(sHost);
int nPort = extractHostPort(sHost, exchange);

return sHost == null
return sName == null
? frame.assignValue(aiResult[0], xBoolean.FALSE)
: frame.assignValues(aiResult, xBoolean.TRUE,
xString.makeHandle(sHost), xUInt16.INSTANCE.makeJavaLong(nPort));
xString.makeHandle(sName), xUInt16.INSTANCE.makeJavaLong(nPort));
}

/**
Expand Down Expand Up @@ -660,9 +664,8 @@ private int invokeRespond(Frame frame, ObjectHandle[] ahArg)

// ----- helper methods ------------------------------------------------------------------------

protected static String getHostName(HttpExchange exchange)
protected static String extractHostName(String sHost)
{
String sHost = exchange.getRequestHeaders().getFirst("Host");
if (sHost != null)
{
int ofPort = sHost.lastIndexOf(':');
Expand All @@ -674,9 +677,8 @@ protected static String getHostName(HttpExchange exchange)
return sHost;
}

protected static int getHostPort(HttpExchange exchange)
protected static int extractHostPort(String sHost, HttpExchange exchange)
{
String sHost = exchange.getRequestHeaders().getFirst("Host");
if (sHost == null)
{
return exchange.getRemoteAddress().getPort();
Expand Down Expand Up @@ -899,13 +901,16 @@ protected static class Router
public void handle(HttpExchange exchange)
throws IOException
{
String sHost = getHostName(exchange);
RouteInfo route = mapRoutes.get(sHost);
if (route == null)
String sHost = exchange.getRequestHeaders().getFirst("Host");
String sName = extractHostName(sHost);
int nPort = extractHostPort(sHost, exchange);
boolean fTls = exchange instanceof HttpsExchange;
RouteInfo route = mapRoutes.get(sName);
if (route == null || nPort != (fTls ? route.nHttpsPort : route.nHttpPort))
{
System.err.println("*** Request for unknown host: " + sHost
+ exchange.getRequestURI());
exchange.sendResponseHeaders(444, -1); // HttpStatus.NoResponse
System.err.println("*** Request for unregistered route: "
+ (fTls ? "https://" : "http://") + sHost + exchange.getRequestURI());
exchange.sendResponseHeaders(421, -1); // HttpStatus.MisdirectedRequest
}
else
{
Expand Down Expand Up @@ -934,7 +939,8 @@ protected void setDirectRoute(RouteInfo route)
}
}

protected record RouteInfo(RequestHandler handler, KeyStoreHandle hKeyStore, String sTlsKey) {}
protected record RouteInfo(RequestHandler handler, int nHttpPort, int nHttpsPort,
KeyStoreHandle hKeyStore, String sTlsKey) {}


// ----- ObjectHandles -------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.xvm.runtime.TypeComposition;

import org.xvm.runtime.template.xBoolean;
import org.xvm.runtime.template.xException;
import org.xvm.runtime.template.xNullable;

import org.xvm.runtime.template.text.xString;
Expand Down Expand Up @@ -107,8 +108,8 @@ public int getReferent(Frame frame, RefHandle hTarget, int iReturn)
hValue = frame.getInjected(sResource, typeResource, hOpts);
if (hValue == null)
{
return frame.raiseException("Unknown injectable resource \"" +
typeResource.getValueString() + ' ' + sResource + '"');
return frame.raiseException(
xException.unknownInjectable(frame, typeResource, sResource));
}

if (Op.isDeferred(hValue))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.xvm.runtime.Frame;
import org.xvm.runtime.ObjectHandle;

import org.xvm.runtime.template.xException;
import org.xvm.runtime.template.xNullable;
import org.xvm.runtime.template.xService;

Expand Down Expand Up @@ -77,8 +78,8 @@ public int invokeNativeN(Frame frame, MethodStructure method, ObjectHandle hTarg
ObjectHandle hValue = frame.getInjected(hName.getStringValue(), hType.getDataType(), hOpts);
if (hValue == null)
{
return frame.raiseException("Unknown injectable resource \"" +
hType.getDataType().getValueString() + ' ' + hName.getStringValue() + '"');
return frame.raiseException(xException.unknownInjectable(frame,
hType.getDataType(), hName.getStringValue()));
}

return Op.isDeferred(hValue)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,12 @@ public static ExceptionHandle abstractMethod(Frame frame, String sMethod)
return makeHandle(frame, "No implementation for \"" + sMethod + '"');
}

public static ExceptionHandle unknownInjectable(Frame frame, TypeConstant type, String sName)
{
return makeHandle(frame, "Unknown injectable resource \"" + type.getValueString() +
' ' + sName + '"');
}


// ---- ObjectHandle helpers -------------------------------------------------------------------

Expand Down
Loading

0 comments on commit ccd521a

Please sign in to comment.